xanoutas/solidity-security-findings huggingface dataset:
Royalty Payment Invariant Violation
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/tree/main/smart-contracts/MinterContract.sol#L408
https://github.com/code-423n4/2023-10-nextgen/tree/main/smart-contracts/MinterContract.sol#L418


# Vulnerability details

## Impact
The vulnerability in the payment mechanism of the smart contract significantly impacts the protocol's functionality. The root cause of the vulnerability is that, despite the README stating an invariant that "Payments can only be made when royalties are set, the artist proposes addresses and percentages, and an admin approves them," poorly managed status control allows the admin to accept addresses and percentages without requiring an artist's proposal. This oversight breaks the stated invariants and has several negative consequences.
```solidity
// File: README.md
178:- Payments can only be made when royalties are set, the artist proposes addresses and percentages, and an admin approves them. // <= FOUND
```

## Proof of Concept
To demonstrate this vulnerability, an admin can accept addresses and percentages without requiring an artist's proposal, resulting in unauthorized royalty payments to the team wallet.
1. The admin, due to the poorly managed status control, can accept addresses and percentages without waiting for the artist to make a proposal.
```solidity
// File: smart-contracts/MinterContract.sol
408:    function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {// <= FOUND: Payments can be made skipping royalties set and the artist proposes.
409:        collectionArtistPrimaryAddresses[_collectionID].status = _statusPrimary;
410:        collectionArtistSecondaryAddresses[_collectionID].status = _statusSecondary;
411:    }
```
2. This allows the admin to proceed to obtain all royalties to the team wallet via the `payArtist` function.
```solidity
// File: smart-contracts/MinterContract.sol
415:    function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
...
418:        require(collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage + _teamperc1 + _teamperc2 == 100, "Change percentages");// <= FOUND: artistPercentage is 0 if skipped previous steps. Admin can chose _teamperc1 + _teamperc2 = 100% to obtain all royalties
        ...
444:    }
```
3. The protocol's payment functionality is compromised, and the invariant is not upheld.
4. Further, this violation can lead to other scenarios, such as the admin resetting the artist/team split even after approval or an artist front-running the admin's approval with a different proposal against the admin's intention.

## Tools Used
Manual Review

## Recommended Mitigation Steps
To mitigate this issue, it is recommended to extend the status control mechanism into multiple stages, such as "INIT," "PERCENTAGE_SPLIT_SET,"
High possibility of DOS
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# 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#L87
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L65


# Vulnerability details

## Impact
In the `claimAuction` function there is a high possibility of DOS where the auction winner is unable to claim the NFT due to high gas cost or not enough gas, this is due to the functions having three loops on same array of all bids, they are in the `returnHighestBid`, `returnHighestBidder` and also in the `claimAuction` function.

## Proof of Concept
Claiming a popular auction might be difficult due to this, as there will be a lot of bidders and bids could make looping through the auctionData array very difficult or impossible in that same block.

## Tools Used
Manual Review

## Recommended Mitigation Steps
- Restructure the function `claimAuction`, it can be reduced to one loop
- use mappings instead of arrays for bids and have separate mapping for definite results, like highestBidders, or highestBids of an auction mapping


## Assessed type

DoS
Adding a randomizer to a collection should be mandatory
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The minting process will be broken.

## Proof of Concept
In the current setup, a randomizer contract can be associated with each collection, and it plays a crucial role in generating a random value for token uniqueness during the minting process.

Here's a breakdown of the process:

1. Initially, a collection doesn't have a randomizer. An admin can add a randomizer using the `addRandomizer` function. Importantly, this step is currently not mandatory to proceed with the collection setup and initiate the sale.

2. If a randomizer is not set for a collection, the collection will lack a randomizer contract, and the associated address will be `address(0)`.

3. However, there's a potential issue in the `_mintProcessing()` function. This function in `NextGenCore.sol` attempts to call the `calculateTokenHash()` function in the randomizer contract linked to the collection ID. If no randomizer is set, this call will fail, leading to transaction reversal and breaking the entire minting process.

This issue needs attention to ensure a smooth minting process, even when a randomizer is not explicitly set for a collection. Consideration should be given to handle scenarios where a randomizer is not defined to prevent transaction failures.

## Tools Used
VSCode

## Recommended Mitigation Steps
Given the crucial role of the randomizer contract in the minting process, it's important to implement a solution that ensures a smooth workflow, even when a randomizer hasn't been explicitly set for a collection. Here are two potential approaches:

**Set Default Randomizer:**
Consider setting a default randomizer contract for collections where a randomizer hasn't been explicitly defined. This default randomizer could serve as a fallback, preventing transaction failures and ensuring the continuity of the minting process.

**Make Randomizer Addition Mandatory:**
Alternatively, you can make it mandatory to add a randomizer before progressing to the next step, specifically before executing the `setCollectionCosts()` function. This ensures that each collection has a valid randomizer contract associated with it before moving forward in the setup process:

<br/><img src="https://1631743732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3qI2FLgAYXA3Xwo3vYpc%2Fuploads%2FpYwHsszhwMuBMxJSI3vI%2Fmodular-Page-2.drawio%20(4).png?alt=media&token=93362763-3054-4b64-b2bf-700b69d5f40b" />

Choosing between these approaches depends on the overall design goals and the desired user experience. Both options address the potential issue highlighted in the `_mintProcessing()` function:


## Assessed type

Invalid Validation
When the burnToMint function is enabled, any bad actor can transfer the nft-to-burn when it receives the newly minted nft, getting burned after he no longer is the owner.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Medium impact, it affects the functionallity of the nfts with other contracts, as they wouldn't want to interact with tokens that could get burned.

## Explanation
in the `NextGenCore` contract, the `burnToMint` function has the minting of the new nft, which makes an external call via `_safeMint`, before the burning of the nft-to-burn. This allows any bad actor to transfer the nft to a victim contract without the victim contract being able to stop the `_burn` from happening.

## Recommended Mitigation Steps

Make the mint of the nft in `burnToMint` happen after the burning of the nft that gives access to the mint.


## Assessed type

Token-Transfer
NFT Claiming Issue Due to Lacking Ownership
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The vulnerability in the AuctionDemo contract has a significant impact on the ability of auction winners to claim their NFTs. The root cause of the vulnerability is that the AuctionDemo contract fails to check whether it owns or has approval to transfer the NFT token being auctioned before open participation. If the contract doesn't own the token or have the necessary approval, the winner will be unable to claim the auctioned NFT.

## Proof of Concept
To demonstrate this vulnerability, consider a scenario in which the admin starts an auction in the AuctionDemo contract via `minter.mintAndAuction` call but sets the recipient for the NFT to an address that is not equal to `address(AuctionDemo)`. When a participant becomes the winner and attempts to claim the NFT, the contract fails to transfer it due to the lacking ownership.
1. An admin calls `minter.mintAndAuction` to start an auction, but the recipient for the NFT token is set to an address that doesn't belong to the AuctionDemo contract.
2. Participants are allowed to join the auction via the `participateToAuction` function, and one of them becomes the winner.
3. When the winner attempts to claim the NFT, the AuctionDemo contract fails to transfer the NFT to the winner, as it doesn't own the NFT or have approval to transfer it.

## Tools Used
Manual Review

## Recommended Mitigation Steps
To mitigate this issue, it is recommended to implement a check to ensure that the AuctionDemo contract either owns the NFT or has the necessary approval to transfer the token before allowing participants to join the auction. 

```patch
// 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);
+          require(IERC721(gencore).ownerOf(_tokenid) == address(this), "NFT not owned");
61:    }
```


## Assessed type

Access Control
Owner of the token will not receive the funds of the highest bid after an Auction is claimed
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
After the auction is completed, the winner or protocol owner must call the claimAuction function. At this point, the token is sent to the auction participant who made the highest bid, and the funds from that bid are sent to the owner of the protocol. And not to the original owner of the NFT.

Funds should be sent to the original owner of the NFT because this can be understood from the description of bad cases in the project description: "Consider ways in which the owner of the token will not receive the funds of the highest bid after an Auction is claimed."

## Proof of Concept
1. The winner of auction call claimAuction()
2. Nft transfers from ownerOfNft to winner
```solidity
IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);
```
3. Funds transfers to owner of protocol
```solidity
 (bool success, ) = payable(owner()).call{value: highestBid}("");
```

## Tools Used
Manual review
## Recommended Mitigation Steps
```diff
 function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
       ...
        for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
            if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
                IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);
-               (bool success, ) = payable(owner()).call{value: highestBid}("");
+               (bool success, ) = payable(ownerOfToken).call{value: highestBid}("");
              ...
        }
    }
```


## Assessed type

Other
No Chainlink error handling in case of ethereums gas prices increasing or subscription running out of Link.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Any collections making use of the ChainLink VRF2 randomizer could potentially get 0x0 hashes for their nfts.
Due to ``uint32 public callbackGasLimit = 40000;`` being hardcoded, any gas fluctuations on Ethereum main net, could potentially not be enough for the oracle to perform the callback & give the minted nfts their unique hashes.
Users are also allowed to mint nfts, if the subscription has run out of Link, guaranteeing a 0x0 hash.
This could be specially terrible, if users decide to mint in high amounts or the max allowed amount per wallet, for all the minted nfts will have the same hash.


## Tools Used
Remix, Hardhat, Foundry

## Recommended Mitigation Steps
Add proper error handling for situations where subscriptions or oracle callbacks might be delayed or never occur.


## Assessed type

Oracle
The absence of sanity checks in the `MinterContract#mintAndAuction()` function can lead to avoidable error scenarios.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact

The `setCollectionCosts()` function within the `MinterContract` is utilized to establish the collection costs and sales model for an upcoming collection sale. As outlined in the [documentation](https://seize-io.gitbook.io/nextgen/nextgen-smart-contracts/minter#introduction), the expectation is that one token can be minted and auctioned during each time period. Therefore, it is crucial to invoke the `setCollectionCosts()` function and specify a non-zero time period before executing `mintAndAuction()`.

However, a vulnerability exists in the `mintAndAuction()` contract as it fails to ensure that the time period is greater than zero. This flaw can result in a division by zero error when the time period is zero. Additionally, an arithmetic underflow error may occur if the `allowlistStartTime` is not set in the `setCollectionPhases()` function.


## Proof of Concept

1. Line 287 can cause arithmetic underflow error if `allowlistStartTime` is not set
2. Line 292 can cause a division by zero error when the `time period` is zero

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

```solidity
285:if (lastMintDate[_collectionID] == 0) {
286:        // for public sale set the allowlist the same time as publicsale
287: @>         timeOfLastMint = collectionPhases[_collectionID].allowlistStartTime - collectionPhases[_collectionID].timePeriod;
288:        } else {
289:            timeOfLastMint =  lastMintDate[_collectionID];
290:        }
291:        // uint calculates if period has passed in order to allow minting
292: @>     uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[_collectionID].timePeriod;
```

```solidity
import "forge-std/Test.sol";
import "../../smart-contracts/NextGenCore.sol";
import "../../smart-contracts/NextGenAdmins.sol";
import "../../smart-contracts/RandomizerNXT.sol";
import "../../smart-contracts/XRandoms.sol";
import "../../smart-contracts/MinterContract.sol";
import "../../smart-contracts/NFTdelegation.sol";
import "../../smart-contracts/AuctionDemo.sol";
import "../../smart-contracts/ERC721.sol";

contract MintAuction is Test {
    NextGenCore public nextGenCore;
    NextGenAdmins public nextGenAdmin;
    NextGenRandomizerNXT public nextGenRandomizerNXT;
    randomPool public xRandoms;
    NextGenMinterContract public nextGenMinter;
    DelegationManagementContract public delegationManager;
    auctionDemo public auctionContract;

    address public owner;
    address public admin;
    address public artist;

    string _collectionName;
    string _collectionArtist;
    string _collectionDescription;
    string _collectionWebsite;
    string _collectionLicense;
    string _collectionBaseURI;
    string _collectionLibrary;
    string[]
No function to distribute secondary sales royalties split.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact

The minter contract currently does not have a way to reliably share 
the secondary sales revenue for the proposed addresses and splits.


## Proof of Concept

Contract : ` NextGenMinterContract `

The minter contract uses  ` collectionArtistSecondaryAddresses `  and ` collectionRoyaltiesSecondarySplits ` mappings to track the addresses and percentage splits for revenue obtained from secondary royalties.

The contract uses `payArtist()` function to split the primary sales revenue.

However, the contract has no such function to dispatch the secondary sales revenue trustably.

## Tools Used

Manual Analysis

## Recommended Mitigation Steps

Employ an access controlled function to split secondary royalties reliably.


## Assessed type

Other
[M-01] Data in **collectionAdditionalData** can be changed even after setting the data by calling **setCollectionData** function 
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The function **setCollectionData** can be called more than once till the **collectionTotalSupply** isnt changed. This can give rise to many issues like : 

1) **reservedMaxTokensIndex** can be changed even after setting the details of the collection. This can be done by first calling the **setCollectionData** function with _collectionTotalSupply as 0 and then after sometime calling this function again , but this time setting the correct values. These occurences can distrupt the protocol. 

2) The values like **collectionArtistAddress** can also be changed even after the artist has signed the collection.  

## Proof of Concept
Here is a scenario : 

1) A Collection is created by the functional admin and correspoding to the same collectionID the collection data is filled but with _collectionTotalSupply as 0 and with _collectionArtistAddress as the address of the artist of the collection 

```
if (collectionAdditionalData[_collectionID].collectionTotalSupply == 0) {
            collectionAdditionalData[_collectionID].collectionArtistAddress = _collectionArtistAddress;
            collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases;
            collectionAdditionalData[_collectionID].collectionCirculationSupply = 0;
            collectionAdditionalData[_collectionID].collectionTotalSupply = _collectionTotalSupply;
            collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint;
            collectionAdditionalData[_collectionID].reservedMinTokensIndex = (_collectionID * 10000000000);
            collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
            wereDataAdded[_collectionID] = true;
```

2) The artist not questioning anything signs the collectionID by calling the artistSignature

```
function artistSignature(uint256 _collectionID, string memory _signature) public {
        require(msg.sender == collectionAdditionalData[_collectionID].collectionArtistAddress, "Only artist");
        require(artistSigned[_collectionID] == false, "Already Signed");
        artistsSignatures[_collectionID] = _signature;
        artistSigned[_collectionID] = true;
    }
```

3) But once this is done , the collection admin can once again call the function this time setting a valid totalSupply and with different **_collectionArtistAddress** address. 
## Tools Used
Manual Review 

## Recommended Mitigation Steps
Consider adding a check check in function **setCollectionData** for parameter **_collectionTotalSupply** to be not equal to 0. 
```
function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collec
Old tokenData is used instead of new
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
When the `burnToMint()` function is called, a token from one collection is burned and a new token from a new collection is minted. The oldest `tokenData`  is transferred to the newly minted token, which is incorrect.

`_mintProcessing(mintIndex, ownerOf(_tokenId), tokenData[_tokenId], _mintCollectionID, _saltfun_o);`


The term `tokenData` refers to additional data that will be stored on-chain for each minted token. The data for every token is expected to be different and once set, `tokenData` can not be changed in the future.

This design may introduce potential issues if a user wishes to store different data on-chain and no longer use the old `tokenData`.

## Recommended Mitigation Steps
Add the possibility for the user to change `tokenData` when using `burnToMint()`.





## Assessed type

Context
Collection randomizer can be updated while collection is frozen
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The current design allows for the Randomizer contract to be modified at any time, even when the collection is in a frozen state. This unrestricted capability poses a risk of disruptions and unfair activities during the minting process.

## Proof of Concept
The `addRandomizer()` function grants the function admin the ability to set or modify the randomizer contract for any collection at any time. Despite its name suggesting addition, it actually facilitates modifications as well.

Ideally, the `freezeCollection` function should provide a means for admins to freeze collection data for transparency on the blockchain, ensuring fairness for users participating in token minting. In the current scenario, however, the option to update the randomizer for a collection remains active even after the collection is frozen.

## Tools Used
VSCode

## Recommended Mitigation Steps
Add the following check to the addRandomizer function:

```solidity
require(collectionFreeze[_collectionID] == false, "collection is frozen");
```


## Assessed type

Invalid Validation