Platform: Code4rena
Start Date: 09/02/2024
Pot Size: $60,500 USDC
Total HM: 17
Participants: 283
Period: 12 days
Judge:
Id: 328
League: ETH
Rank: 193/283
Findings: 3
Award: $3.51
π Selected for report: 0
π Solo Findings: 0
π Selected for report: Abdessamed
Also found by: 0rpse, 0xAlix2, 0xAsen, 0xCiphky, 0xlemon, 0xmystery, 0xvj, ADM, Aamir, Archime, BARW, DarkTower, Draiakoo, FloatingPragma, JCN, McToady, MrPotatoMagic, OMEN, PetarTolev, Ryonen, SpicyMeatball, Tendency, VAD37, Velislav4o, VrONTg, Zac, adamn000, ahmedaghadi, alexxander, alexzoid, bhilare_, btk, cats, d3e4, denzi_, devblixt, dimulski, evmboi32, fnanni, givn, haxatron, immeas, jesjupyter, juancito, ke1caM, klau5, korok, krikolkk, matejdb, n0kto, niser93, peter, pkqs90, radin100, shaka, sl1, soliditywala, stackachu, stakog, t0x1c, vnavascues, yotov721, zhaojohnson
1.2667 USDC - $1.27
Main invariant broke due to bad access validation
As you can see on https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L233-L262 the only restrictions to mint fighter NFT from 'FighterFarm::redeemMintPass' are to be the owner of mintPassToken and equal array lengths, which mean that any user with mintPassToken ownership could choose the fighter and icon type, which makes all unique NFTs not unique anymore
Import requires right into 'FighterFarm::redeemMintPass' that paste limits on the users choices for their future fighter NFT properties
Access Control
#0 - c4-pre-sort
2024-02-22T07:29:14Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T07:29:20Z
raymondfam marked the issue as duplicate of #33
#2 - c4-pre-sort
2024-02-26T00:52:59Z
raymondfam marked the issue as duplicate of #1626
#3 - c4-judge
2024-03-05T10:54:15Z
HickupHH3 marked the issue as satisfactory
π Selected for report: klau5
Also found by: 0xAleko, 0xAlix2, 0xAsen, 0xCiphky, 0xKowalski, 0xlemon, 0xvj, 14si2o_Flint, Aamir, AlexCzm, Aymen0909, BARW, Blank_Space, DanielArmstrong, Davide, Draiakoo, Giorgio, McToady, MrPotatoMagic, PoeAudits, Ryonen, Silvermist, SpicyMeatball, Tychai0s, VAD37, Varun_05, alexxander, alexzoid, aslanbek, blutorque, btk, cats, d3e4, denzi_, evmboi32, fnanni, givn, grearlake, haxatron, jesjupyter, juancito, ke1caM, ktg, lanrebayode77, linmiaomiao, matejdb, merlinboii, n0kto, novamanbg, nuthan2x, petro_1912, pynschon, radin100, sashik_eth, shaka, sl1, soliditywala, solmaxis69, t0x1c, ubl4nk, vnavascues, xchen1130, yotov721, zhaojohnson
1.1225 USDC - $1.12
Break invariant due to bad validation or missed logic
Details: The main part of the problem is that in 'FighterFarm.sol::reRoll' function users are allowed select any fighter type they want and there could be mismatch with the actual fighter type that comes from the given id. This could lead to extra reRolls for the fighter type with less maxReRollsAllowed
Proof of Code: !!!Note that before running this code you should change the numElements mapping from 'FighterFarm.sol::incrementGeneration' to avoid any zero division reverts from 'FighterFarm.sol::_createFighterBase'!!!
function testExtraRerolls() public { address user = makeAddr("USER"); // Minting fighter to user with fighterType 0 _mintFromMergingPool(user); _fundUserWith4kNeuronByTreasury(user); // Incrementing generation for fighterType 1 vm.prank(_ownerAddress); _fighterFarmContract.incrementGeneration(1); uint8 tokenId = 0; uint8 fighterType = 1; _neuronContract.addSpender(address(_fighterFarmContract)); vm.startPrank(user); _fighterFarmContract.reRoll(tokenId, fighterType); _fighterFarmContract.reRoll(tokenId, fighterType); _fighterFarmContract.reRoll(tokenId, fighterType); _fighterFarmContract.reRoll(tokenId, fighterType); vm.stopPrank(); assert( _fighterFarmContract.numRerolls(0) > _fighterFarmContract.maxRerollsAllowed(0) ); }
There two options to solve this problem depends on the application logic:
Change the figtherType to be equal to given one
function reRoll(uint8 tokenId, uint8 fighterType) public { ... ... ... + fighters[tokenId].dendroidBool = bool(fighterType); fighters[tokenId].element = element; fighters[tokenId].weight = weight; fighters[tokenId].physicalAttributes = _aiArenaHelperInstance .createPhysicalAttributes( // view function!!! newDna, generation[fighterType], fighters[tokenId].iconsType, fighters[tokenId].dendroidBool ); _tokenURIs[tokenId] = ""; }
}
Revert if fighters[tokenId]'s fighterType != fighterType
function reRoll(uint8 tokenId, uint8 fighterType) public { +require(fighters[tokenId].dendroidBool == bool(fighterType)) ... ... ... }
}
Invalid Validation
#0 - c4-pre-sort
2024-02-22T00:11:45Z
raymondfam marked the issue as insufficient quality report
#1 - c4-pre-sort
2024-02-22T00:11:52Z
raymondfam marked the issue as duplicate of #17
#2 - c4-pre-sort
2024-02-22T00:50:01Z
raymondfam marked the issue as sufficient quality report
#3 - c4-pre-sort
2024-02-22T00:50:09Z
raymondfam marked the issue as not a duplicate
#4 - c4-pre-sort
2024-02-22T00:50:18Z
raymondfam marked the issue as duplicate of #405
#5 - c4-pre-sort
2024-02-22T01:00:47Z
raymondfam marked the issue as duplicate of #306
#6 - c4-judge
2024-03-05T04:29:27Z
HickupHH3 marked the issue as satisfactory
#7 - c4-judge
2024-03-19T09:05:07Z
HickupHH3 changed the severity to 3 (High Risk)
π Selected for report: haxatron
Also found by: 0xAlix2, 0xCiphky, 0xStriker, 0xaghas, 0xbranded, 0xlamide, 0xmystery, 0xvj, 14si2o_Flint, Aamir, AgileJune, Aymen0909, DanielArmstrong, DarkTower, Draiakoo, EagleSecurity, Giorgio, Krace, KupiaSec, MidgarAudits, MrPotatoMagic, PoeAudits, Ryonen, SpicyMeatball, Topmark, Tychai0s, VAD37, Varun_05, VrONTg, WoolCentaur, _eperezok, alexxander, alexzoid, aslanbek, blutorque, btk, cartlex_, d3e4, devblixt, evmboi32, fnanni, immeas, jesjupyter, juancito, ke1caM, klau5, ktg, lil_eth, merlinboii, nuthan2x, peter, petro_1912, pkqs90, pynschon, radin100, sandy, sashik_eth, shaka, sl1, soliditywala, t0x1c, ubl4nk, visualbits, vnavascues
1.1225 USDC - $1.12
DoS of main function due to dividing by 0
Details: There many different scenarios about this issue, but the main part is that after single FighterType's generation increment, all functions that use to execute 'FighterFarm.sol::_createFighterBase' for this FighterType is going to revert no matter the input values are, because 'numElements[generation[fighterType]]' from uint256 element implementation(on L470) will always give zero. Here one example scenario.
Scenario:
Proof of Code: Import the code below in FighterFarm.t.sol and don't forget to add import {stdError} from "forge-std/StdError.sol"; at the beginning:
function testClaimFightersRevertsAfterIncrementGeneration() public { // Owner(address(this)) increment generation _fighterFarmContract.incrementGeneration(0); // Pepearing variables for 'FighterFarm.sol::claimFighters' uint8[2] memory numToMint = [1, 0]; bytes memory claimSignature = abi.encodePacked( hex"407c44926b6805cf9755a88022102a9cb21cde80a210bc3ad1db2880f6ea16fa4e1363e7817d5d87e4e64ba29d59aedfb64524620e2180f41ff82ca9edf942d01c" ); string[] memory claimModelHashes = new string[](1); claimModelHashes[ 0 ] = "ipfs://bafybeiaatcgqvzvz3wrjiqmz2ivcu2c5sqxgipv5w2hzy4pdlw7hfox42m"; string[] memory claimModelTypes = new string[](1); claimModelTypes[0] = "original"; vm.expectRevert(stdError.divisionError); _fighterFarmContract.claimFighters( numToMint, claimSignature, claimModelHashes, claimModelTypes ); }
To prevent this from happening consider implementing some logic into 'FighterFarm.sol::incrementGeneration' that will update the numElements mapping like shown below
function incrementGeneration(uint8 fighterType, uint8 newNumElements) external returns (uint16) { require(msg.sender == _ownerAddress); generation[fighterType] += 1; maxRerollsAllowed[fighterType] += 1; +numElements[generation[fighterType]] = newNumElements; return generation[fighterType]; }
Note that both fighterTypes is going to have the same number of elements
Consider adding new mapping that points to numElements with figtherType and generation given
Think of using numElements as constant value
Add updateElement function to provide only admin/owner changes to numElement
DoS
#0 - c4-pre-sort
2024-02-22T18:24:09Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T18:24:23Z
raymondfam marked the issue as duplicate of #45
#2 - c4-judge
2024-03-07T06:54:25Z
HickupHH3 marked the issue as satisfactory