xanoutas/solidity-security-findings huggingface dataset:
Insufficient Signature Verification Logic
Audit: 2023-12-revolutionprotocol-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

```

        // Ensure signature is valid
        if (recoveredAddress == address(0) || recoveredAddress != from) revert INVALID_SIGNATURE();

        return true;
```
The logical` OR ( || )` operator implies that if the  recoveredAddress  is not zero, the second condition `( recoveredAddress != from )`will be checked. 

If the first condition is true (i.e.,  `recoveredAddress == address(0)` ), the second condition won't be evaluated because the overall statement will already be true.

This approach does not fully validate the signature, making it susceptible to exploitation.
## Impact
an attacker could bypass the validation by ensuring that the recovered address is not the zero address and is not equal to the  from  address. This could allow them to reuse the signature for unauthorized transactions, undermining the integrity and security of the system.

## Proof of Concept

```
     // Ensure signature is valid
        if (recoveredAddress == address(0) || recoveredAddress != from) revert INVALID_SIGNATURE();
```
If the first condition is true there won't be a check if the `recoveredAddress ` is from which will lead to reuse of the same signature.

## Tools Used
Manual Review 

## Recommended Mitigation Steps
For short term Change to 
```
// Validate recovered address and signature
    require(recoveredAddress != address(0) && recoveredAddress == from, "Invalid signature");
```
For long term fix Utilize established cryptographic libraries or built-in functions specifically designed for signature verification. These libraries typically offer comprehensive validation mechanisms, reducing the likelihood of vulnerabilities and exploits. Like the OpenZeppelin ECDSA lib.


## Assessed type

Invalid Validation
ArtPieces created during token auction will have excess quorum requirement if token gets no bids and is burned
Audit: 2023-12-revolutionprotocol-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Art piece will have inflated quorum which might be impossible to reach

## Proof of Concept
Consider the following POC
```
function testArtPieceCreatedWithExcessQuorumVotesRequirement() public {
        vm.stopPrank();
        //create art piece
        uint256 firstPieceId = voter1Test.createDefaultArtPiece();

        //Auction the created art piece (piece passes quorum)
        vm.startPrank(address(dao));
        auction.unpause();

        //verb token is minted for auction
        console2.log(erc721Token.totalSupply()); // 1


        //create new art piece
        uint256 secondPiece = voter1Test.createDefaultArtPiece();
        //quorum is 200000000000000000 as the newly minted verb token is included in 
        token total supply
        //used for calculating quorum
        console2.log(cultureIndex.getPieceById(secondPiece).quorumVotes); 
        //200000000000000000

        //auction ends with no bids and token is burned
        vm.warp(block.timestamp + auction.duration() + 1);
        auction.pause();
        auction.settleAuction();
        vm.stopPrank();

        //token supply is back to 0 since minted token is burned
        //but the previously created piece's quorum is still 200000000000000000 which is 
        impossible to reach currently
        console2.log(erc721Token.totalSupply()); // 0 

        console2.log(cultureIndex.getPieceById(secondPiece).quorumVotes); 
        //200000000000000000

        //subsequent pieces are created with correct quorum
        uint256 fourth = voter1Test.createDefaultArtPiece();
        console2.log(cultureIndex.getPieceById(fourth).quorumVotes); //0
    }
```
The above tests demonstrates that the second created piece has an inflated quorum which might be impossible to reach.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Consider subtracting the verb token balanceOf for the auction contract from the erc721Token total supply when a new art piece is being created (i.e taking a snapshot of all distributed tokens at art piece creation).


## Assessed type

Invalid Validation
There will be ETH locked in ERCTokenEmitter and its amount will increase every day, after each auction is settled
Audit: 2023-12-revolutionprotocol-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## tl;dr
When any user buys `NontransferableERC20Votes` tokens (including `AuctionHouse` when auctions are settled) and `creatorRateBps != 0`, there will be `ETH` left in `ERC20TokenEmitter` and there is no way to transfer it out.

## Detailed description
Users can buy `NontransferableERC20Votes` by calling `ERC20TokenEmitter::buyToken`. 

This function accepts some amount of `ETH`. Some part of received `ETH` is transferred to the protocol rewards contract. The remaining part (`msgValueRemaining`) is distributed as follows:
- `toPayTreasury = (msgValueRemaining * (10_000 - creatorRateBps)) / 10_000` is directly transferred to the treasury contract
- `((msgValueRemaining - toPayTreasury) * entropyRateBps) / 10_000` is transferred to `creatorsAddress`

Assuming `entropyRateBps > 0` (and, obviously `< 10_000`), we may notice that `((msgValueRemaining - toPayTreasury) * entropyRateBps) / 10_000 < msgValueRemaining - toPayTreasury`. 

Hence
`toPayTreasury + ((msgValueRemaining - toPayTreasury) * entropyRateBps) / 10_000 < toPayTreasury + (msgValueRemaining - toPayTreasury) = msgValueRemaining`, which means that there will be some non transferred `ETH` left in the contract.

The exact amount will depend on the value of `entropyRateBps` and `creatorRateBps`, but for a test with `entropyRateBps = creatorRateBps = 3000`, when `1 ETH` is paid to `ERC20TokenEmitter::buyToken`, there is `~0.02 ETH` left in the contract, which is `2%` of total `ETH` paid (see PoC section for the test showing that).

## Impact
Considerable amount of `ETH` transferred to `ERC20TokenEmitter` will be stuck there forever. This amount could as well be distributed as rewards or to some other contract in order to use it, for instance, for further project development, but right now, it will just be wasted.

## Proof of Concept
First of all, there are only two places where `ETH` is transferred out of `ERC20TokenEmitter`:
- `buyToken`
- `_depositPurchaseRewards`

As I have shown before, `buyToken` will (almost) always send out less tokens than it receives.

`_depositPurchaseRewards` is `internal` and only called  in `_handleRewardsAndGetValueToSend`, that in turn, is only called in `buyToken`, so there is no way to transfer out excessive `ETH` that was transferred to `ERC20TokenEmitter` via `buyToken`.

In order to test the issue, please put the following code into `AuctionSettling.t.sol` and run it. It will output the amount of `ETH` stuck, assuming that `buyToken` was called with `1 ETH`:
```solidity
    // create an auction with a piece of art with given number of creators and finish it
    function _createAndFinishAuction() internal
    {
        uint nCreators = 10;
        address[] memory creatorAddresses = new address[](nCreators);
        uint256[] memory creatorBps = new uint2
Signature Replay Vulnerability in `CultureIndex.sol` Due to Missing Chain ID
Audit: 2023-12-revolutionprotocol-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## High Issue Report: 

### Impact
The `CultureIndex.sol` contract in its current implementation is vulnerable to signature replay attacks across different blockchain networks. This issue arises because the `voteHash` calculation does not include the chain ID. In a multi-chain deployment scenario, as described in the project documentation, the same signature could be replayed on different chains, leading to unauthorized actions or exploitation.

### Proof of Concept
- **Location of Issue**: [CultureIndex.sol#L431](https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L431)
- **Current Implementation**:
  The `voteHash` is calculated without including the chain ID, making it susceptible to replay attacks on different chains.

### Tools Used
- Manual review of the smart contract code.

### Recommended Mitigation Steps
- Modify the `voteHash` calculation to include the chain ID. This can be achieved by using the `CHAINID` opcode or similar mechanisms available in the Solidity language to retrieve the current chain ID.
- The updated `voteHash` calculation should look something like this:
  ```solidity
  bytes32 voteHash = keccak256(abi.encode(VOTE_TYPEHASH, from, pieceIds, nonces[from]++, deadline, block.chainid));



## Assessed type

Invalid Validation
Protocol is Losing Excess Reward due to Precision Rounding down
Audit: 2023-12-revolutionprotocol-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/protocol-rewards/src/abstract/RewardSplits.sol#L44-L51
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/protocol-rewards/src/abstract/RewardSplits.sol#L56-L62
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/protocol-rewards/src/abstract/RewardSplits.sol#L17-L21


# Vulnerability details

## Impact
Protocol would continuously incur avoidable cumulative loss in reward due to rounding down in every single transaction in the RewardSplits.sol contract
## Proof of Concept
```solidity
   // 2.5% total
    uint256 internal constant DEPLOYER_REWARD_BPS = 25;
    uint256 internal constant REVOLUTION_REWARD_BPS = 75;
    uint256 internal constant BUILDER_REWARD_BPS = 100;
    uint256 internal constant PURCHASE_REFERRAL_BPS = 50;

```
From The state declaration codes above it can be noted that cummulative overall reward should be 2.5% of transaction amount.
```solidity
function computeTotalReward(uint256 paymentAmountWei) public pure returns (uint256) {
        if (paymentAmountWei <= minPurchaseAmount || paymentAmountWei >= maxPurchaseAmount) revert INVALID_ETH_AMOUNT();

        return
 >>>           (paymentAmountWei * BUILDER_REWARD_BPS) /
            10_000 +
            (paymentAmountWei * PURCHASE_REFERRAL_BPS) /
            10_000 +
            (paymentAmountWei * DEPLOYER_REWARD_BPS) /
            10_000 +
            (paymentAmountWei * REVOLUTION_REWARD_BPS) /
            10_000;
    }
```
The function above shows how each reward is calculated individually, the point of interest that should be noted is the presence of 4 division operation in a single mathematical calculation.
```solidity

    function computePurchaseRewards(uint256 paymentAmountWei) public pure returns (RewardsSettings memory, uint256) {
        return (
            RewardsSettings({
>>>                builderReferralReward: (paymentAmountWei * BUILDER_REWARD_BPS) / 10_000,
>>>                purchaseReferralReward: (paymentAmountWei * PURCHASE_REFERRAL_BPS) / 10_000,
>>>                deployerReward: (paymentAmountWei * DEPLOYER_REWARD_BPS) / 10_000,
>>>               revolutionReward: (paymentAmountWei * REVOLUTION_REWARD_BPS) / 10_000
            }),
            computeTotalReward(paymentAmountWei)
        );
    }
```
The problem is with the way this reward percentage value are calculated, The presence of many division operation hints the definite loss of value due to rounding down, at no point in the computeTotalReward(...) & computePurchaseRewards(...) functions is this loss accounted for, to prove this loss a very simple math values would be used just to paint an idea of this vulnerability. 
 - step 1
sample amount = 9,999
using the calculation methods provided in the code in the contract
 - step 2
builderReferralReward = 9,999 * 100 / 10,000 = 99;
purchaseReferralReward = 9,999 * 50 / 10,000 = 49;
deployerReward = 9,999 * 25 /
If the NFT is because the auction is not met the `reservePrice` in `_settleAuction()`  function, during the auction the totalSupply of erc721VotingToken is get in the quorumVotes, leading that the piece cannot be drpped
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#L1


# Vulnerability details

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

## 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

## Recommended Mitigation Steps


## Assessed type

Context
Error Handling and Consistency in '_settleAuction' Function
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#L336


# Vulnerability details

**Potential Risk:**
The '_settleAuction' function is responsible for settling an auction by finalizing the bid and handling payouts to various parties. It performs several operations and interactions with external contracts. However, the function lacks proper error handling and consistency in its execution. In case of errors or exceptions during any of these operations, the contract might not handle the situation gracefully, leading to unexpected behavior and potential loss of funds.

**Proof of Concept (PoC):**
Consider a scenario where an error occurs during the execution of the '_settleAuction' function:

- If the 'verbs.burn' or 'verbs.transferFrom' functions fail, they might not revert the transaction, potentially leading to inconsistent contract states.
- If an error occurs during the 'erc20TokenEmitter.buyToken' function call, the contract does not handle the error, potentially resulting in a loss of ether without minting tokens as intended.

**Recommended Mitigation Steps:**
To improve error handling and consistency in the '_settleAuction' function and mitigate potential risks, consider the following steps:

1. Implement proper error handling for interactions with external contracts (e.g., 'verbs.burn', 'verbs.transferFrom', 'erc20TokenEmitter.buyToken'). Ensure that transactions are reverted in case of errors.
2. Use the 'try-catch' construct to handle exceptions and revert transactions when necessary.
3. Emit specific error events or log error messages to provide transparency and debugging information.
4. Ensure that the contract state remains consistent, especially in cases where actions like burning or transferring tokens are involved.

Here's a recommended solution with these improvements:

function _settleAuction() internal {
    IAuctionHouse.Auction memory _auction = auction;

    require(_auction.startTime != 0, "Auction hasn't begun");
    require(!_auction.settled, "Auction has already been settled");
    //slither-disable-next-line timestamp
    require(block.timestamp >= _auction.endTime, "Auction hasn't completed");

    auction.settled = true;

    uint256 creatorTokensEmitted = 0;

    // Check if contract balance is greater than reserve price
    if (address(this).balance < reservePrice) {
        // If contract balance is less than reserve price, refund to the last bidder
        if (_auction.bidder != address(0)) {
            if (!_safeTransferETHWithFallback(_auction.bidder, _auction.amount)) {
                // Handle transfer failure, possibly revert
                revert("Failed to refund to the last bidder");
            }
        }

        // And then burn the Verb
        if (!verbs.burn(_auction.verbId)) {
            // Handle burn failure, possibly revert
            revert("Failed to burn the Verb");
        }
    }
Error Handling in '_createAuction' Function
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#L309


# Vulnerability details

**Potential Risk:**
The '_createAuction' function attempts to mint a new Verb by calling the 'verbs.mint()' function. However, it lacks proper error handling for the minting process. If the minting operation fails (e.g., due to insufficient gas or other reasons), the contract immediately pauses, potentially disrupting the functionality of the contract and affecting its users.

**Proof of Concept (PoC):**
Consider a scenario where the 'verbs.mint()' function fails to mint a new Verb:

// Simulate a failure in 'verbs.mint()' by reverting
function mint() external returns (uint256) {
    revert("Mint failed");
}

// Call '_createAuction'
_createAuction();

In this PoC, the 'verbs.mint()' function is intentionally made to revert, simulating a minting failure. As a result, the '_createAuction' function catches the error and pauses the contract. This behavior could disrupt the contract's operations and impact users.

**Recommended Mitigation Steps:**
To improve error handling in the '_createAuction' function and mitigate potential risks, consider implementing more robust error handling by distinguishing between different types of errors and handling them appropriately. Specifically:

1. Catch specific exceptions that indicate minting failures and handle them gracefully.
2. Implement error logging or emit specific error events to provide transparency and debugging information.

Here's a recommended solution:

function _createAuction() internal {
    // Check if there's enough gas to safely execute token.mint() and subsequent operations
    require(gasleft() >= MIN_TOKEN_MINT_GAS_THRESHOLD, "Insufficient gas for creating auction");

    try verbs.mint() returns (uint256 verbId) {
        uint256 startTime = block.timestamp;
        uint256 endTime = startTime + duration;

        auction = Auction({
            verbId: verbId,
            amount: 0,
            startTime: startTime,
            endTime: endTime,
            bidder: payable(0),
            settled: false
        });

        emit AuctionCreated(verbId, startTime, endTime);
    } catch Error(string memory mintError) {
        // Handle specific minting errors gracefully
        // Example: emit an error event or log the error message
        emit MintingError(mintError);
    } catch {
        // Handle other unexpected errors gracefully
        // Example: emit a general error event or log the error message
        emit UnexpectedError("An unexpected error occurred during auction creation");
    }
}

In this solution:

- We catch specific exceptions that indicate minting failures and handle them gracefully, providing better error reporting and handling.
- We also catch unexpected errors with a general catch block and emit an appropriate error event or log the error message for debugging purposes.

By
Input Validation for 'createBid' Function
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#L171


# Vulnerability details

**Potential Risk:**
The 'createBid' function in the contract is responsible for allowing users to place bids on a Verb auction by sending Ether. While the function includes several checks, it lacks explicit input validation for certain parameters, which could lead to potential issues if the provided parameters are not valid or expected.

**Proof of Concept (PoC):**
Consider a scenario where a malicious user calls the 'createBid' function with invalid input parameters:

// Invalid input: Zero address for 'bidder'
createBid(123, address(0));

In this PoC, the 'createBid' function is called with a zero address for 'bidder.' The lack of input validation checks allows this invalid value to be accepted during the bid creation process, potentially causing runtime errors or issues in the contract.

**Recommended Mitigation Steps:**
To enhance input validation in the 'createBid' function and mitigate potential risks, consider adding input validation checks for the following conditions:

1. Ensure that 'bidder' is a valid non-zero Ethereum address.

Here's a recommended solution:

function createBid(uint256 verbId, address bidder) external payable override nonReentrant {
    IAuctionHouse.Auction memory _auction = auction;

    require(bidder != address(0), "Bidder cannot be a zero address");
    require(_auction.verbId == verbId, "Verb not up for auction");
    require(block.timestamp < _auction.endTime, "Auction expired");
    require(msg.value >= reservePrice, "Must send at least reservePrice");
    require(
        msg.value >= _auction.amount + ((_auction.amount * minBidIncrementPercentage) / 100),
        "Must send more than the last bid by minBidIncrementPercentage amount"
    );

    address payable lastBidder = _auction.bidder;

    auction.amount = msg.value;
    auction.bidder = payable(bidder);

    // Extend the auction if the bid was received within 'timeBuffer' of the auction end time
    bool extended = _auction.endTime - block.timestamp < timeBuffer;
    if (extended) auction.endTime = _auction.endTime = block.timestamp + timeBuffer;

    // Refund the last bidder, if applicable
    if (lastBidder != address(0)) _safeTransferETHWithFallback(lastBidder, _auction.amount);

    emit AuctionBid(_auction.verbId, bidder, msg.sender, msg.value, extended);

    if (extended) emit AuctionExtended(_auction.verbId, _auction.endTime);
}

In this solution:

- We've added an input validation check to ensure that 'bidder' is a valid non-zero Ethereum address.
- This change helps prevent the use of invalid or zero addresses, enhancing the input validation of the 'createBid' function.

By implementing this solution, you can reduce the risk of issues related to invalid or unexpected input parameters when users create bids.


## Assessed type

Invalid Validation