xanoutas/solidity-security-findings huggingface dataset:
M-06 Unmitigated
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code




# Vulnerability details

Mitigation of M-06: NOT mitigated

## Mitigated issue
[M-06: NFTs can be transferred even if StakeAtRisk remains, so the user's win cannot be recorded on the chain due to underflow, and can recover past losses that can't be recovered(steal protocol's token)](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/137)

There are two possibilities of revert due to underflow triggered in `RankedBattle.updateBattleRecord()`.
1. In `RankedBattle._addResultPoints_()`: [`accumulatedPointsPerAddress[fighterOwner][roundId] -= points`](https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L486). The impact is that a fighter with accumulated points, which is transferred to a new address cannot be recorded in a loss. 
2. In `StakeAtRisk.reclaimNRN()`: [`amountLost[fighterOwner] -= nrnToReclaim;`](https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/StakeAtRisk.sol#L104). The impact is that a fighter with some stake at risk cannot be recorded in a win until it has lost.

Both of the above only apply to the round in which the fighter was transferred.

There was also an impact reported that a transferred fighter could be used to reclaim losses from a previous round. I consider this aspect invalid, since the new owner cannot gain more than the old owner could (re)gain. It might however be considered an issue that a fighter with stake at risk can be transferred since this is almost the same as transferring a staked fighter. This does not quite seem to be the initial issue reported, but it [is fixed anyway by fix 1490](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/14/files#diff-bcde603c412d351d31a22361f1593f9d9ac1e73c65754d4dda3e80033aa0e415R293).

## Mitigation review - mootly mitigated and causes an even worse DoS.
A new variable `addressStartedRound[tokenId][roundId]` has been added, with [a check that reverts if the owner of the `tokenId` has changed from a previous call in the round](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/RankedBattle.sol#L375-L380). That is, only fights under the first owner can be updated.
So this now reverts in a superset of the original cases. It balances the exploitability for profit, but now any fighter transfer will cause a DoS of the game server trying to call `updateBattleRecord()`. If a fighter is transferred then all matches with this fighter will lead to a revert. This can be quite significant. If fighters are paired at random and 10% of fighters have been transferred then over 19% of all matches will revert. Since there is no time in between rounds, this will be an issue whenever a fighter is transferred. The round id is also not emitted when a fighter is transferred so it would be difficult for the game server to fairly exclude transferred fighters.

This is perhaps an error rather than a
M-05 Unmitigated
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code




# Vulnerability details

Mitigation of M-05: NOT mitigated, with error, see comments

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L574

## Mitigated issue(s)
[M-05: Can mint NFT with the desired attributes by reverting transaction](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/376)
(Also see duplicated reports [#1017](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/1017), [#578](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/578), [#1991](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/1991))

There were four issues with the randomness of the DNA in FighterFarm.sol:
1. The user can retry the DNA set in `_createNewFighter()` by reverting the `onERC721Received()` hook.
2. The user can brute force his `msg.sender` which seeds the DNA in `reRoll()` and `claimFighters()`.
3. The user can wait for an appropriate `fighters.length` which seeds the DNA in `mintFromMergingPool()` and `claimFighters()`.
4. The user can select the best out of all rerolls, which can be calculated in advance.

(The issue of freely setting DNA in `mintFromMergingPool()` is part of [H-03: Players have complete freedom to customize the fighter NFT when calling redeemMintPass and can redeem fighters of types Dendroid and with rare attributes](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/366).)

Additionally, a mitigation of [#578](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/578), which was duplicated to [M-05 (#376)](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/376), has been attempted. This issue was about the DNA simply being differently generated, due to a likely mistake, but with low impact.

[M-05: Can mint NFT with the desired attributes by reverting transaction](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/376) is only 1. above, and I consider the other issues (including #578) to have been incorrectly or misleadingly duplicated to M-05, and I have to deal with them as separate/new issues/errors.
I have submitted reports on 2-4 as three new issues, as well as a report on the error from the mitigation of #578. I will make use of this submission as the report of an unmitigated 1., the details on which and recommended mitigation steps follow at the end of this report, after an overview of the review of these issues and the error.
The mitigation review of the part of the scope which is "M-05" thus consists of a total of 5 reports:
1. This report.
2. "User influence on DNA in `claimFighters()` (unmitigated issue 2. grouped under M-05)"
3. "User influence on DNA via `fighters.length` in `mintFromMergingPool()` (unmitigated issue 3. grouped under M-05)"
4. "The user can select the best out of all rerolls (unmitigated issue 4. grouped under M-05)"

   Error. "[M-05/#578] Mitigation error: user influence on DNA via `to`"

## Mitigation re- and overvie
M-03 Unmitigated
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/fix-47/src/MergingPool.sol#L137-L175


# Vulnerability details

# Lines of code
### Old lines of code
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/MergingPool.sol#L134-L167

### Mitigated lines of code
https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/fix-47/src/MergingPool.sol#L137-L175

# Vulnerability details
[M-03 (#932)](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/932) reports that `Fighter created by mintFromMergingPool can have arbitrary weight and element`.

[FighterFarm.mintFromMergingPool()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L307-L331) can be called only by the [MergingPool.claimRewards()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/MergingPool.sol#L134-L167) method:

```
MergingPool.sol#L134-L167

134      /// @notice Allows the user to batch claim rewards for multiple rounds.
135      /// @dev The user can only claim rewards once for each round.
136      /// @param modelURIs The array of model URIs corresponding to each round and winner address.
137      /// @param modelTypes The array of model types corresponding to each round and winner address.
138      /// @param customAttributes Array with [element, weight] of the newly created fighter.
139      function claimRewards(
140          string[] calldata modelURIs, 
141          string[] calldata modelTypes,
142          uint256[2][] calldata customAttributes
143      ) 
144          external 
145      {
146          uint256 winnersLength;
147          uint32 claimIndex = 0;
148          uint32 lowerBound = numRoundsClaimed[msg.sender];
149          for (uint32 currentRound = lowerBound; currentRound < roundId; currentRound++) {
150              numRoundsClaimed[msg.sender] += 1;
151              winnersLength = winnerAddresses[currentRound].length;
152              for (uint32 j = 0; j < winnersLength; j++) {
153                  if (msg.sender == winnerAddresses[currentRound][j]) {
154                      _fighterFarmInstance.mintFromMergingPool(
155                          msg.sender,
156                          modelURIs[claimIndex],
157                          modelTypes[claimIndex],
158                          customAttributes[claimIndex]
159                      );
160                      claimIndex += 1;
161                  }
162              }
163          }
164          if (claimIndex > 0) {
165              emit Claimed(msg.sender, claimIndex);
166          }
167      }
```

`MergingPool.claimRewards()` is used to claim rewards, i.e., to mint a new fighter from the merging pool for each round where the player wins. When a player calls `MergingPool.claimRewards()`, he/she can pass the `customAttributes` parameter, which is not checked anywhere. This array is passed to `FighterFarm.mintFromMergingPool()`:

```
FighterFarm.sol#L307-L331

307      /// @notice Mints a new fighter from t
M-05B Unmitigated
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/setUpAirdrop-mitigation/src/FighterFarm.sol#L366


# Vulnerability details

# Lines of code

### Old lines of code
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L324

### Mitigated lines of code
https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/setUpAirdrop-mitigation/src/FighterFarm.sol#L366

# Vulnerability details
The issue was reported in [#578](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/578) and [#1017](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/1017).

The vulnerability is inside [FighterFarm.mintFromMergingPool()](https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L307-L331):

```
FighterFarm.sol#L307-L331

307      /// @notice Mints a new fighter from the merging pool.
308      /// @dev Only the merging pool contract address is authorized to call this function.
309      /// @param to The address that the new fighter will be assigned to.
310      /// @param modelHash The hash of the ML model associated with the fighter.
311      /// @param modelType The type of the ML model associated with the fighter.
312      /// @param customAttributes Array with [element, weight] of the newly created fighter.
313      function mintFromMergingPool(
314          address to, 
315          string calldata modelHash, 
316          string calldata modelType, 
317          uint256[2] calldata customAttributes
318      ) 
319          public 
320      {
321          require(msg.sender == _mergingPoolAddress);
322          _createNewFighter(
323              to, 
324              uint256(keccak256(abi.encode(msg.sender, fighters.length))), 
325              modelHash, 
326              modelType,
327              0,
328              0,
329              customAttributes
330          );
331      }
```

This function can be called only by the `merging pool contract`. This means that `msg.sender` must be `_mergingPoolAddress`.
However, `msg.sender` is also used as `dna` parameter of `_createNewFighter()` (line [L324](https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L324)). 

**Impact**: Even if an attacker can't exploit this bad randomness to obtain better fighters, players could forecast the attributes of fighters that will be created in the future, due to the bad randomness caused by this issue.

# Recommended Mitigation proposed by wardens
The mitigation proposal is to replace `msg.sender` in line [L324](https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L324) with the address `to`, that should represents the player who calls [MergingPool.claimRewards()](https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/MergingPool.sol#L139-L167):

`
M-05A Unmitigated
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/setUpAirdrop-mitigation/src/FighterFarm.sol#L241
https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/setUpAirdrop-mitigation/src/FighterFarm.sol#L424


# Vulnerability details

# Lines of code
### Old lines of code
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L214
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L379

### Mitigated lines of code
https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/setUpAirdrop-mitigation/src/FighterFarm.sol#L241
https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/setUpAirdrop-mitigation/src/FighterFarm.sol#L424

# Vulnerability details

The issue was reported in [#1017](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/1017).

It describes 4 impacts:
1. DNA malipulation in [FighterFarm.reRoll()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L379). It was mitigated in [#16](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/16/commits/255e72b14f124f643003f0cde8eaacaec9ed42e9).
2. DNA malipulation in [FighterFarm.mintFromMergingPool()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L313). It was mitigate in [#3](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/3/files).
3. DNA malipulation in [FighterFarm.redeemMintPass()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L233). It was mitigated in [#10](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/10/commits/370b0a02d99d7ade4bd04b9c9b784f56b478e841).
4. DNA malipulation in [FighterFarm.claimFighters()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L191). It was mitigated in [#11](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/11/commits/03d35bd8522ae07fc84474c32978bd58fa20ecb8).

The M-05A mitigation aims to mitigate 1) and 4).

The vulnerabilities rely on the fact that `dna` depends on an external input that can be used by a malicious
player to obtain rare `fighters`. In detail, in both of them the computation of `dna` depends on `msg.sender`
and other parameters that can foreseen. A malicious player can create many wallet, or could use [Create2](https://docs.alchemy.com/docs/create2-an-alternative-to-deriving-contract-addresses)
to create a contract at wanted address.

# Mitigation applied by developers

```diff
FighterFarm.claimFighters()

@@ -220,7 +220,7 @@ contract FighterFarm is ERC721, ERC721Enumerable {
        for (uint16 i = 0; i < totalToMint; i++) {
            _createNewFighter(
                msg.sender, 
-               uint256(keccak256(abi.encode(msg.sender, fighters.length))),
+               uint256(keccak256(abi.encode(msg.sender, nftsClaimed[msg.sender][0], nftsClaimed[msg.sender][1]))),
                modelHashes[i], 
                modelTypes[i],
                i < numToM
FighterFarm.reRoll() method works wrong and allows minting wanted attributes
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/setUpAirdrop-mitigation/src/FighterFarm.sol#L412-L436


# Vulnerability details

# Impact
Each `fighter` has a specific number of max reRolls, according to `fighterType`. This means that the owner of the `fighter` can call `FighterFarm.reRoll()` at most `maxRerollsAllowed` times, in order to obtain better fighter's attributes.

We want to underline three aspects:

* `FighterFarm.reRoll()` operation has a cost in NRN
* `numRerolls` of a specific `fighter` is not reset when it is transfered
* `dna` is the only value used to compute `fighter`'s traits. After [mitigation](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/11/commits/255e72b14f124f643003f0cde8eaacaec9ed42e9), `dna` depends just on `tokenId` and `numRerolls[tokenId]`

Because the reasons above, the owner of a `fighter` can always forecast what is the best number of `reRolls`.
So, a cunning player should always improve its `fighter`'s traits using the right number of `reRolls`. For this reason, we could expect that all `fighters` will be reRolled until they reach the best number of `reRolls`.
Furthermore, a malicious player can wait for the right `tokenId` which can be used in `reRoll` operation to obtain a very rare fighter.

### Remaining reRolls of a fighter don't increase its value
We asked in a private thread a clarification on the `FighterFarm.reRoll()` mechanism. This was the answer:

```
I: I've another question on reRoll method. A fighter can be reRolled several times. 
The limit is the MasRerollsAllowed value. When a fighter is transferred from a player to other,
the numRerolls value is not reset. This means that the onwer can't reRoll the receive fighter, if
the previous owner used all roll changes. Also this is a wanted behavior?

Dev: Yes this is intended. You can think of this as someone potentially paying a premium for an NFT that has 
more reRolls remaining. They should be intrinsically more valuable since they have more optionality.
```

While this was true before the mitigation, now the `dna` doesn't depend on `msg.sender` anymore. This means that the outcomes of `reRoll` operations made by the seller is the same of the outcomes obtained by the buyer. If they are both cunning players, they know before the transfer if that `fighter` would improve using `FighterFarm.reRoll()` operation or not.
We want to underline that this mechanism strongly changes after the mitigation. As long as the outcome of `reRoll` operation depended on `msg.sender`, buying a `fighter` with remaining `reRoll` operations made sense, because buyer `reRoll` operations would have different outcome then the seller ones.

After mitigation, seller and buyer can reach the same rare attributes. They both should be aware on the best outcome of `reRoll` operation. If not, it could happen because one or both of them are not cunning: the transfer could be not fair, impacting the game and the market.

So, after mitiga
M-03 Unmitigated
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/MergingPool.sol#L158-L169


# Vulnerability details

### C4 issue
M-03: [Fighter created by mintFromMergingPool can have arbitrary weight and element](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/932)

### Comments
When users minted new fighters through the MergingPool, validation for `weight` and `element` values, passed as input in the `customAttributes` array, was missing. Therefore, winners of MergingPool NFTs could arbitrarily assign any `weight` and `element` to their new fighters. 

### Mitigation
[PR #16](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/16)
The fixed implemented introduces input validation for the custom attributes provided in `MergingPool::claimRewards`. `element` is required to be smaller than the total number of possible elements for the current generation, while `weight` is required to be in the [65, 95] range:

```solidity
require(customAttributes[j][0] < _fighterFarmInstance.numElements(generation), "MergingPool: element out of bounds");
require(customAttributes[j][1] >= 65 && customAttributes[j][1] <= 95, "MergingPool: weight out of bounds");
```

Users calling claimRewards provide one pair of customAttribute per claimable NFT. However, the `customAttributes` index [checked](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/MergingPool.sol#L159-L160) is not the appropriate index `claimIndex` but the `winnerAddresses` index `j`. 

The most concerning consequence of this bug is that the custom attribute values could bypass the element and weight requirements if the custom attribute index for a given claim is greater than the max number of winners of the rounds iterated. For example, if there is 1 winner per round for several rounds in a row and a player wins two rounds, `customAttributes[1]` would not be checked and `customAttributes[0]` would be checked repeatedly.

### Suggestion
Change
```solidity
for (uint32 j = 0; j < winnersLength; j++) {
    require(customAttributes[j][0] < _fighterFarmInstance.numElements(generation), "MergingPool: element out of bounds");
    require(customAttributes[j][1] >= 65 && customAttributes[j][1] <= 95, "MergingPool: weight out of bounds");
    if (msg.sender == winnerAddresses[currentRound][j]) {
        _fighterFarmInstance.mintFromMergingPool(
            msg.sender,
            modelURIs[claimIndex],
            modelTypes[claimIndex],
            customAttributes[claimIndex]
        );
        claimIndex += 1;
    }
}
```
to:
```solidity
for (uint32 j = 0; j < winnersLength; j++) {
    if (msg.sender == winnerAddresses[currentRound][j]) {
        require(customAttributes[claimIndex][0] < _fighterFarmInstance.numElements(generation), "MergingPool: element out of bounds");
        require(customAttributes[claimIndex][1] >= 65 && customAttributes[claimIndex][1] <= 95,
It's not possible to claim MergingPool rewards for the last round, only for rounds previous to it
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/1192a55963c92fb4bd9ca8e0453c96af09731235/src/MergingPool.sol#L153


# Vulnerability details

### C4 issue
M-04: [DoS in MergingPool::claimRewards function and potential DoS in RankedBattle::claimNRN function if called after a significant amount of rounds passed](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/868)

### Comments
Previously, The `MergingPool::claimRewards` function loop could exceed the block gas limit, potentially causing a DoS. This would happen if a user tried claiming their rewards after too many rounds had passed. Similarly, there was a risk of DoS in `RankedBattle::claimNRN` for the same reason.

In both cases, rounds were iterated up to the current round ID non inclusively.

### Mitigation
[PR #18](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/18)
Now the issue in both functions is fixed thanks to an additional input `uint32 totalRoundsToConsider` which allows users to loop fewer rounds per call. However, the input validation of `totalRoundsToConsider` in `MergingPool::claimRewards` is incorrect:

```solidity
    require(lowerBound + totalRoundsToConsider < roundId, "MergingPool: totalRoundsToConsider exceeds the limit");
    uint8 generation = _fighterFarmInstance.generation(0);
    for (uint32 currentRound = lowerBound; currentRound < lowerBound + totalRoundsToConsider; currentRound++) {
```

`lowerBound + totalRoundsToConsider` can at most be equal to `roundId - 1`, which means that claimRewards() will loop, at most, till `roundId - 2`. Therefore, it's not possible to claim MergingPool rewards for the last round, only for rounds previous to it.

Note that this was [correctly implemented](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/1192a55963c92fb4bd9ca8e0453c96af09731235/src/RankedBattle.sol#L333) in the `RankedBattle::claimNRN` fix.

### Suggestion
Change
```solidity
    require(lowerBound + totalRoundsToConsider < roundId, "MergingPool: totalRoundsToConsider exceeds the limit");
```
to
```solidity
    require(lowerBound + totalRoundsToConsider <= roundId, "MergingPool: totalRoundsToConsider exceeds the limit");
```

### Conclusion
The mitigation works well but introduces an issue because the new function input is wrongly validated.


## Assessed type

Invalid Validation