xanoutas/solidity-security-findings huggingface dataset:
Failure in Delegation of Minting Permissions
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
When the admin calls the `setCollectionCosts()` function, the _delAddress param is intended to delegate minting permissions to a specific user. However, the delegation does not actually occur. 

In the context of admin delegation, the isAllowedToMint check relies on a delegation address set during the `setCollectionCosts()` call, which in turn calls `retrieveGlobalStatusOfDelegation()`. This function fetches the length of the globalDelegationHashes mapping, which is expected to represent the delegation status. The issue arises because this mapping returns 0 for the corresponding hash, indicating no delegation, unless a value is explicitly set using the `registerDelegationAddress()` function. This flaw prevents the delegated user from minting on behalf of the admin, impacting the functionality and reliability of the smart contract.

## Proof of Concept
1. Call the setCollectionCosts() function to delegate minting permissions.
2. Observe that the isAllowedToMint check fails despite correct delegation parameters.
3. Check the globalDelegationHashes mapping return value for the corresponding hash.


## Tools Used
vscode

## Recommended Mitigation Steps
Push the delegated user into the globalDelegationHashes during the `setCollectionCosts()` function call in order to update the mappings.





## Assessed type

Context
Dust amount stuck in `NextGenMinterContract` contract
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
`NextGenMinterContract` contract distributes earnings via `payArtist` function. The function computes payment of each artist & royalty and sends it to corresponding addresses. Since, there is no floating point athematic in solidity, the dust (difference in total amount and sum of payments of each artist & royalty) resulting due to uint256 athematic is not sent to the recepients. 

## Proof of Concept
The [`payArtist` function](https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L415) of `NextGenMinterContract` contract computes artist and royalty payment as follows :-
```
    function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
        require(collectionArtistPrimaryAddresses[_collectionID].status == true, "Accept Royalties");
        require(collectionTotalAmount[_collectionID] > 0, "Collection Balance must be grater than 0");
        require(collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage + _teamperc1 + _teamperc2 == 100, "Change percentages");
        uint256 royalties = collectionTotalAmount[_collectionID];
        collectionTotalAmount[_collectionID] = 0;
        address tm1 = _team1;
        address tm2 = _team2;
        uint256 colId = _collectionID;
        uint256 artistRoyalties1;
        uint256 artistRoyalties2;
        uint256 artistRoyalties3;
        uint256 teamRoyalties1;
        uint256 teamRoyalties2;
        artistRoyalties1 = royalties * collectionArtistPrimaryAddresses[colId].add1Percentage / 100;
        artistRoyalties2 = royalties * collectionArtistPrimaryAddresses[colId].add2Percentage / 100;
        artistRoyalties3 = royalties * collectionArtistPrimaryAddresses[colId].add3Percentage / 100;
        teamRoyalties1 = royalties * _teamperc1 / 100;
        teamRoyalties2 = royalties * _teamperc2 / 100;

        // send share and emit events
    }
```
Since sum of `artistRoyalties1, artistRoyalties2, artistRoyalties3, teamRoyalties1, teamRoyalties2` will not be equal to royalties in most of the cases, therefore, there will always be some dust left after each call to `payArtist` function which will not be sent to recipients. The dust may be of more value in future due to rise in eth price.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Modify the `payArtist` function to send balance `royalties` to `teamRoyalties2` as follows
```
        teamRoyalties2 = royalties - (artistRoyalties1 + artistRoyalties2 + artistRoyalties3 + teamRoyalties1);
```





## Assessed type

Math
MinterContract.mint division by zero
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The users would not be able to mint tokens if it implies a periodic sales model with the time period set to zero or not set. Also, the admins would be unable to mint and auction for the same reason.

## Proof of Concept
Let's suppose the following scenario takes place:
1. Collection admin sets collection sales option to 3 and timePeriod to 0 by calling `setCollectionCosts`.
2. Alice tries to mint the token by calling the `mint` function; however, it will always revert with `with panic code 0x12 (Division or modulo division by zero)`, which does not provide any context and users/admins without technical background would not be able to recognise the source of issue.

The reason is hidden in the evaluation if a period has passed to allow minting. Instances:
```
249:    uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[col].timePeriod;

292:    uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[_collectionID].timePeriod;
```
[249](https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L249), [292](https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L292)

## Tools Used
Manual Review

## Recommended Mitigation Steps
In `setCollectionCosts`, add a check for the `_timePeriod` parameter to be above zero if `_salesOption` equals 3. For instance:
```
if (_salesOption == 3) {
    require(_timePeriod > 0, "Time Period Not Set");
}
```



## Assessed type

Error
Possible loss of funds for bidders trying to participate in an auction
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
A bidder can bid for an auction the same time an auction is being finalized(claimed) and depending on which is executed first, it's possible for a bidder to lose his funds.

## Proof of Concept

```
function participateToAuction(uint256 _tokenid) public payable {
        require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
        auctionInfoStru memory newBid = auctionInfoStru(msg.sender, msg.value, true);
        auctionInfoData[_tokenid].push(newBid);
    }
```

Participating in an auction is available when `msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true`.

The important detail here is that: `block.timestamp <= minter.getAuctionEndTime(_tokenid)` - keep in mind it's **<=**.

```
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
        require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
        auctionClaim[_tokenid] = true;
        uint256 highestBid = returnHighestBid(_tokenid);
        address ownerOfToken = IERC721(gencore).ownerOf(_tokenid);
        address highestBidder = returnHighestBidder(_tokenid);
        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}("");
                emit ClaimAuction(owner(), _tokenid, success, highestBid);
            } else if (auctionInfoData[_tokenid][i].status == true) {
                (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
                emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
            } else {}
        }
    }
```

Claiming an auction can be done when `block.timestamp >= minter.getAuctionEndTime(_tokenid)` - again keep in mind it's **<=**, which means **participating** and **claiming** an auction can be done in the same **block.timestamp** which can be a problem depending on which transaction is executed first, because if the `claimAuction` is executed before `participateToAuction` and in the same **block.timestamp**, bidder's bid will be lost because there are no checks to see in `participa
Malicious winner can hold an auction hostage
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
A contract that wins an auction can postpone owner & refundee’s payments indefinitely.

## Proof of Concept

At the time of winning, an Auction holds the owner’s sell fee (equal to what the winning bid is) and also holds extra funds from the non-winning bids. Upon concluding an auction it is expected that the owner & refundees receive their payments. To distribute these fees either an Admin or the winner of the auction has to call `claimAuction(...)`. The issue is that a malicious actor can bid & win through a contract that has a reverting `onERC721Received()` hook function. In that case `claimAuction(...)` will revert when it attempts to `safeTransferFrom(...)` the NFT to the malicious bidder. In such a manner a malicious winner can have final authority when and if the owner & refundees get their payments. Note that this does require financial commitment from the malicious winner (i.e he has to win the auction), however the funds that will be withheld will be more than what he commits. 

## Additional Note
The same idea of bricking an auction’s funds and NFT but at significantly cheaper cost (eg 1 wei + gas fees) can be executed by a malicious bidder that front runs the first bid through a contract that implements a “return bomb” (memory expansion & copy attack) in the `fallback()` function - this will cause `claimAuction(...)` to revert when it attempts to refund the 1 wei bidder. This finding however will most likely be deemed OOS because of [L-18] in the bot findigs, nevertheless, I am noting it here for sponsor’s & judge reference since it implies severe consequneces.

## Coded POC

- Run forge init --force
- Place the code from the gist in a test file under `/test`
- POC Gist - https://gist.github.com/alexxander77/0cca44dea3d670e08bd72aaf4d905d35
- run with `forge test --match-test testForcedRevert`
- Output - `claimAuction(...)` reverts

## Tools Used
Manual Inspection

## Recommended Mitigation Steps
Separate the logic of claiming the NFT, paying the owner & refunding refundees.


## Assessed type

DoS
```updateAdminContract``` function admins can escalate their own privileges to that of global admin
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/NextGenCore.sol#L322
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/RandomizerNXT.sol#L45
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/RandomizerRNG.sol#L61
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/RandomizerVRF.sol#L94
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L454


# Vulnerability details

## Impact
The ```updateAdminContract``` function can be used by a malicious function admin to escalate their own privileges to that of the global admin
## Proof of Concept
1. ```NextGenAdmins``` owner/admin assigns alice to be the function admin of ```updateAdminContract```. This means alice has permission to only execute the ```updateAdminContract``` and none of the other privileged functions
2. Alice calls ```updateAdminContract``` with her own admin contract with her registered as the global admin
3. Alice has now removed the previous global admin and has set herself to be the new admin 
```solidity
    function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
        require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
        adminsContract = INextGenAdmins(_newadminsContract);
    }
```
4. alice can now call every function as global admin and has successfully escalated her privileges from ```updateAdminContract``` admin to global admin

## Tools Used
VIM
## Recommended Mitigation Steps
Only allow the owner multisig to have permissions to call the ```updateAdminContract``` function and disallow attempts to set a non-owner function admin for the ```updateAdminContract``` function selector.


## Assessed type

Invalid Validation
Precision Loss in NFT Minting Price Calculation
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Summary
The `getPrice` function in the `minterContract` smart contract determines the minting cost for NFTs. The current implementation, which performs division before multiplication, risks precision loss due to integer arithmetic in Solidity. This can lead to incorrect calculations of the minting cost.

## Impact
Solidity's lack of support for floating-point arithmetic means that division operations result in integer values, truncating any fractional parts. When this division precedes a multiplication, as seen in the `getPrice` function, it can cause a loss of precision. The primary impact is an incorrect minting cost, which could either unfairly benefit users (by undercharging) or harm the contract's profitability (by overcharging).

## Proof of Concept

```solidity
return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
```



## Tools Used
- Manual code review and analysis.

## Recommended Mitigation Steps
1. **Reorder Arithmetic Operations:** Adjust the order of operations to perform multiplication before division. This approach reduces the impact of truncation by leveraging larger numbers in the multiplication first:

    ```solidity
    return collectionPhases[_collectionId].collectionMintCost + (collectionPhases[_collectionId].collectionMintCost * gencore.viewCirSupply(_collectionId) / collectionPhases[_collectionId].rate);
    ```



## Assessed type

Math
NextGenCore#burnToMint#burn - A malicious user could increase burnAmount on arbitrary collection by holding any random token.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## **Impact**

The **`burn`** and **`burnToMint`** functions in the smart contract contain a critical oversight: they do not verify that the **`_tokenId`** being burned corresponds to the **`_collectionID`** provided as an argument. This means a user can pass any **`_collectionID`** when burning a token, which leads to inaccurate tracking of **`burnAmount`** per collection. Consequently, the **`totalSupplyOfCollection`** function, which relies on **`burnAmount`**, will return incorrect data. This vulnerability could be exploited to distort the supply metrics of any collection within the contract.

## **Proof of Concept**

An attacker can exploit this vulnerability as follows:

1. Call the **`burn`** function with a **`_tokenId`** from any collection and provide a different **`_collectionID`** as the argument.
2. The contract does not check if the **`_tokenId`** belongs to the **`_collectionID`** provided.
3. The **`burnAmount`** for the unrelated **`_collectionID`** is incremented, thereby affecting the integrity of the collection's supply metrics.

## **Tools Used**

Manual Review.

## **Recommended Mitigation Steps**

- Implement a verification step in both **`burn`** and **`burnToMint`** functions to ensure the **`_tokenId`** is indeed part of the **`_collectionID`** being specified. This can be achieved by comparing **`_collectionID`** against a mapping of **`tokenIdsToCollectionIds`** to confirm ownership.


## Assessed type

Invalid Validation
The user can lose ETH and not receive a refund during the auction
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Bug Description
To participate in the auction, one needs to invoke the `participateToAuction` function and have the highest bid. To claim the NFT, the `claimAuction` function should be called. These two functions have incorrect auction end time checks, introducing a vulnerability to potential fund losses.

## Proof-of-Concept
The issue lies in the auction end time verification:
```solidity

/// participateToAuction
require( block.timestamp <= minter.getAuctionEndTime(_tokenid));

/// claimAuction
require(block.timestamp >= minter.getAuctionEndTime(_tokenid));
```

So, it is possible to participate and claim the NFT simultaneously.
Let's consider the following scenario:
`Preconditions`: The last highest bid is 8 ETH.

1. Bob participates in the auction (`participateToAuction`) at the last moment (`block.timestamp == auctionEndTime`) with a bid of 10 ETH.
2. Alice frontruns Bob's transaction, participates in the auction (`participateToAuction`) with a bid of 9 ETH, and simultaneously claims the NFT (`claimAuction`), sends ETH to the owner and refunds other users.
3. Bob's transaction executes in the same block and doesn't fail. After this, Bob won't be able to retrieve his funds through the `cancelBid` function.

## Impact
The ETH used to participate in the auction will be lost.

## Tools Used
Manual

## Recommended Mitigation Steps
Consider changing `claimAuction` as follows:
```diff
function claimAuction(
        uint256 _tokenid
    ) public WinnerOrAdminRequired(_tokenid, this.claimAuction.selector) {
        require(
-            block.timestamp >= minter.getAuctionEndTime(_tokenid) &&
+            block.timestamp > minter.getAuctionEndTime(_tokenid) &&
                auctionClaim[_tokenid] == false &&
                minter.getAuctionStatus(_tokenid) == true
        );

		///code
}
```


## Assessed type

Invalid Validation
The artistSignature function does not sign or validate artist signature as stated by the documentation.
Audit: 2023-10-nextgen-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The `artistSignature` function does not sign or validate artist signature as stated by the documentation. There is no check whether the artist signed the collections or an implementation to help artist sign the collections as stated by the documentation.

## Proof of Concept
According to the documentation: 
"The artistSignature(..) function is used by the artists to sign the collections that they have created."
link: https://seize-io.gitbook.io/nextgen/nextgen-smart-contracts/core

Also in the documentation: 
"artist can sign the collection onchain with their addresses for enhanced proverance."

However the `artistSignature(...)` function does not provide onchain signature or even verify if the signature parameter provided by the artist is not an empty string.

```
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; //@audit how do you check that the signature is signed by the artist.
//@audit how do you verify that the collection was signed
        artistSigned[_collectionID] = true;//@audit when an artist makes a mistake the first time that's all for the whole collections. Document says artist can sign the collection onchain with their addresses for enhanced proverance.
    }
```
Nothing shows that the signature passed as parameter above is even a signature on the collections by the artist as stated by the docs.

## Tools Used
Manual review

## Recommended Mitigation Steps
Implement onchain signing of the collection by the artist and the verification as stated in the docs.


## Assessed type

Other