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: 116/283
Findings: 3
Award: $30.00
π Selected for report: 0
π Solo Findings: 0
π 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
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L470 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L500 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L380
in the FighterFarm contract the _createFighterBase function while calculating the (element) variable, the numElements mapping will only map (0) which is the generation of the fighter type to 3 elements, means the fighter at the zero generation will have 3 elements and will revert on any other generation since there is no value set for the numElements to other generations throughout the contract, this means that except for the zero generation, which will have valid value, the mapping (numElements) will return 0 for other fighter generations, when the dna is mod(%) by the 0 it will revert. Hence not allowing fighter to be created or rerolled when called from the respective functions.
function _createFighterBase( uint256 dna, uint8 fighterType ) private view returns (uint256, uint256, uint256) { uint256 element = dna % numElements[generation[fighterType]]; uint256 weight = dna % 31 + 65; uint256 newDna = fighterType == 0 ? dna : uint256(fighterType); return (element, weight, newDna); }
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L470 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L500 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L380 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L110
Manual Review
Ensure that numElements is initialized with a valid non-zero value for each new generation before any fighters of that generation are created. This could be done within the function that increments the generation. the incrementGeneration function could be updated to account for numElements too like this:
function incrementGeneration(uint8 fighterType, uint8 newNumElements) external { require(msg.sender == _ownerAddress, "Only the owner can increment generation"); require(newNumElements > 0, "Number of elements must be greater than zero"); generation[fighterType] += 1; maxRerollsAllowed[fighterType] += 1; numElements[generation[fighterType]] = newNumElements; }
Other
#0 - c4-pre-sort
2024-02-22T19:05:58Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T19:06:09Z
raymondfam marked the issue as duplicate of #45
#2 - c4-judge
2024-03-08T03:18:46Z
HickupHH3 marked the issue as satisfactory
π Selected for report: givn
Also found by: 0x11singh99, 0xAkira, 0xBinChook, 0xDetermination, 0xMosh, 0xStriker, 0xmystery, 14si2o_Flint, 7ashraf, Aamir, AlexCzm, BARW, Bauchibred, BenasVol, BigVeezus, Blank_Space, Bube, DarkTower, DeFiHackLabs, EagleSecurity, KmanOfficial, Krace, McToady, MrPotatoMagic, PetarTolev, Rolezn, SHA_256, SpicyMeatball, Tekken, Timenov, ZanyBonzy, agadzhalov, alexzoid, boredpukar, btk, cartlex_, dimulski, forkforkdog, haxatron, immeas, jesjupyter, juancito, kartik_giri_47538, klau5, lsaudit, merlinboii, nuthan2x, offside0011, oualidpro, peter, radev_sw, rekxor, rspadi, shaflow2, shaka, swizz, vnavascues, yotov721, yovchev_yoan
8.8123 USDC - $8.81
no | Issue | Instances | |
---|---|---|---|
[L-01] | add more validation checks for the input data in the createGameItem() function | 1 | |
[L-02] | the function call will fail if the maxId is more than one | 1 | |
[L-03] | zero nrn distribution | 1 | |
[L-04] | the function adjusts the unstake amount without reverting | 1 | |
[L-05] | it is a best practice to use the safeErc20 library | 12 | |
[L-06] | no zero address checks | 15 |
no | Issue | Instances | |
---|---|---|---|
[N-01] | The values of the attributeProbabilities mapping are redundantly set | 1 | |
[N-02] | the function name could be changed to represent it much clearer | 1 | |
[N-03] | comment suggestion and function implementation difference | 1 | |
[N-04] | redundant code logic | 1 | |
[N-05] | the resetting should be skiped if the value is already set to the same value | 3 |
since the function createGameItem() creates gemeItems that will be in the systme permanently it is a good practice to add some more validation checks for the input data, such as check if the finiteSupply is true, if yes,than the itemsRemaining should be more than zero, and the item price should be more than zero.
if(itemPrice <= 0 ){ revert(); } if (finiteSupply) { if(itemsRemaining <= 0 ) { revert(); } }
In the getFighterPoints() function, the array points is initialized with a length of 1, which will cause the function call to fail if maxId is greater than 1. When the loop tries to access points[i] for i > 1, it will result in an out-of-bounds array access, which will cause a runtime error and revert the transaction.
in the setRankedNrnDistribution() function If the rankedNrnDistribution for a round is set to zero (either intentionally or by mistake), players would receive no rewards for that round, which will be unexpected if they have accumulated points. Its best to add a check for zero before adding the distribution value for the round to the rankedNrnDistribution mapping.
in the function unstakeNRN there is a check where if the amount to be unstaked is more than the amountStaked it will set the amount to be unstaked to the amountStaked and then continue on unstaking the balance, the problem is it could potentially lead to confusion for users. The function allows a user to attempt to unstake more NRN tokens than they actually have staked, and instead of reverting with an error, it silently adjusts the unstake amount to the maximum available, without informing the user that their input was higher than the their stakedAmount. A user might not realize that they unstaked less than they intended.
while the protocol only interacts only with the $NRN token which implements the standard erc20, it is still best practice to use the safERC20 library while interacting with the erc20 functions respectivley (transfer, trnaferFrom, approve) functions.
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L376 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L164 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L132 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L143 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L176 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L189 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L203 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L251 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L283 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L493 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/StakeAtRisk.sol#L100 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/StakeAtRisk.sol#L143
the functions below does not check for zero address while setting important protocol addresses
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L149 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L157 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L165 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L119 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L141 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L187 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/MergingPool.sol#L100 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L95 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L103 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L111 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L120 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L178 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L203 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L211 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/StakeAtRisk.sol#L67
in the constructor of the AiArenaHelper contract the values for the attributeProbabilities are set twice which is redundant, and should be mitigated to set this value once.
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/AiArenaHelper.sol#L45 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/AiArenaHelper.sol#L49
the function danToIndex() in the AiArenaHelper contract name could be changed to represent the function much clearer, and since the function does not take dna as input attribute, it could be misleading. The function name could be changed to calculateAttributeIndex() which represents the function's purpose much clearer.
the function comment suggests that all the arrays should be of the same length but the require statement doesn't check for the iconsTypes array's length. either the iconsTypes should be added to the checks or the comment should be updated.
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L225 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L243
in the setStakeAtRiskAddress() function an address is provided to the function to be set as the _stakeAtRiskInstance but the function first assigns the address to the _stakeAtRiskAddress and then assigns the _stakeAtRiskAddress to the _stakeAtRiskInstance. This is redundant. To fix this redundancy, you can remove the _stakeAtRiskAddress state variable and directly assign the passed address to the function to the _stakeAtRiskInstance while wrapping it in the StakeAtRisk.
the function that includes redundancy https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L192-L196 the redundant state variable https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L69 the place the redundant variable is used which could be replaced with the _stakeAtRiskInstance https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L493
after calculating the stakingFactor the _calculatedStakingFactor mapping is set to true for the tokenId and roundId, this mapping should be checked if it already contains the intended value, then the resetting of the mapping to the same value should be skiped. This mapping is used in the stakeNrn and in the unstakeNrn it is possible that one of these functions for the same values are called many times, and since the _calculatedStakingFactor only stores boolean values it is ok to skip the resetting if the values is already the same as the one the contract wants to reset to. It is the same case with the hasUnstaked mapping in the unstakeNrn function which saves a boolean value. The first time the function is called it will set the value for the tokenId and the roundId to true and if called again this will be reset to the same value which is unnecessary and could be skiped by adding an if statement check.
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L262 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L281 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L282
#0 - raymondfam
2024-02-26T04:32:53Z
Adequate amount of L and NC entailed.
#1 - c4-pre-sort
2024-02-26T04:32:58Z
raymondfam marked the issue as sufficient quality report
#2 - HickupHH3
2024-03-05T10:49:33Z
#1604: R #1593: R #1616: L
#3 - c4-judge
2024-03-11T10:49:45Z
HickupHH3 marked the issue as grade-b
π Selected for report: 0xSmartContract
Also found by: 0xAsen, 0xDetermination, 0xStriker, 0xblack_bird, 0xbrett8571, 0xepley, 0xweb3boy, 14si2o_Flint, Bauchibred, DarkTower, JayShreeRAM, JcFichtner, K42, McToady, Myd, PoeAudits, Rolezn, SAQ, ZanyBonzy, aariiif, albahaca, ansa-zanjbeel, cheatc0d3, clara, cudo, dimulski, fouzantanveer, foxb868, hassanshakeel13, hunter_w3b, kaveyjoe, klau5, peanuts, pipidu83, popeye, rspadi, scokaf, shaflow2, tala7985, wahedtalash77, yongskiws
20.0744 USDC - $20.07
AI Arena is a gaming platform that incorporates human with AI. Users go on to the AI Arena platform, acquire NFTs representing their AI models. The users then train the AI models with a process called imitation learning, which basically means that the AI model observes the user's movements and techniques and learns from it, the more the AI model is trained the better it becomes. These AI models are then submitted to ranked matches and compete in matches with other AI models trained by other users. The winner of the match is payed in $NRN which is the AI Arena native token, and this is the ultimate goal, train the best AI model, compete in ranked matches and win rewards.
In summary AIArena is:
The key contracts of the AI Arena for this audit are
Auditing the key contracts of the AI Arena Protocol is essential to ensure the security of the protocol. These contracts form the backbone of the AI Arena protocol. Focusing on these contracts first will provide a solid foundation for understanding the protocol's operation and how it manages creation of different fighters, calculating battle results, increasing and decreasing a user's rewards.
In auditing these contracts, I examined for possible security risks like reentrancy, access control vulnerabilities, and logic inconsistencies. Moreover, I rigorously tested the functions and roles outlined in these contracts to ensure they operate as intended.
There are several important roles in the protocol.
Consequently, I conducted an analysis and audit of the subject protocol through the following steps:
Core Protocol Contract Overview:
My primary focus was to comprehensively comprehend the code base and offer recommendations for enhancing its functionality. The central objective was to examine the critical contracts and their interplay within the AI Arena Protocol.
I started with the following contracts, which play crucial roles in the AI Arena protocol:
Main Contracts I Looked At this phase
FighterFarm.sol RankedBattle.sol Neuron.sol MergingPool.sol StakeAtRisk.sol
I started my analysis by examining the FighterFarm.sol contract which plays crucial role in the AI Arena protocol and manages the creation and ownership of the AI Arena fighter NFTs. After that I delved into the RankedBattle.sol contract which has the logic for the staking, unstaking and calculating the battle results. the Neuron.sol, MergingPool.sol and the stakeAtRisk.sol, were also thoroughly examined to ensure the secure flow of logic within the contracts.
Documentation Review: Afterward, I proceeded to Review these Docs for a more comprehensive and technical understanding of the AI Arena protocol.
Compiling code and running provided tests: I compiled the code and ran the provided tests.
Manual Code Review: In this phase, I conducted a line-by-line analysis.
Overall, I consider the quality of the AI Arena protocol codebase to be Good. The code appears to be mature and well-developed. The implementation of the code adheres to various standards properly. Details are explained below:
Codebase Quality Categories | Comments |
---|---|
Code Maintainability and Reliability | The codebase demonstrates moderate maintainability with well-structured functions and comments, promoting readability. It exhibits reliability through defensive programming practices, parameter validation, and handling external calls safely. The use of internal functions for related operations enhances code modularity, reducing duplication. Libraries improve reliability by minimizing arithmetic errors. Adherence to standard conventions and practices contributes to overall code quality. However, full reliability depends on external contract implementations like openzeppelin. |
Code Comments | The contracts include comments that describes the purpose and operations of various sections, aiding developers and auditors in comprehending and managing the code. These comments offer insights into methods, variables, and the overarching architecture of the contracts. For instance, the "RankedBattle" contract's code comments furnish crucial details. They declare the title and the objective of the contract, explain all the variables and the functions within the contract. |
Documentation | The documentation of the AI Arena protocol is quite comprehensive and detailed, providing a solid overview of how AI Arena is structured and how its various aspects function. However, what the documentation does not provide is a sub part in the docs that explain each AI Arena smart contract in details, explaining the objectives of the contracts, explaining its methods, specific diagrams representing the internal interactions between the contracts, and how users interact with these contracts. Explaining the contracts with diagrams is a way to gain a deeper understanding of how different contracts interact and the functions they implement. With considerable enthusiasm. I am confident that these diagrams will bring significant value to the protocol as they can be seamlessly integrated into the existing documentation, enriching it and providing a more comprehensive and detailed understanding for users, developers and auditors. |
Testing | The overall line coverage percentage provided by tests is 90% which should be aimed at 100%. |
Code Structure and Formatting | The codebase contracts are well-structured and formatted. It inherits from OpenZeppelin governance, and token standards in some contracts. The constructors initializes the contract with parameters and specified roles, contracts override functions, each component is provided with accompanying comments explaining their purpose. The code is organized, making it readable and maintainable. |
Errors | Custom errors should be used instead of require statements with string errors. Custom errors are easier to re-use and maintain. |
Properly managing these risks and implementing best practices in security and decentralization will contribute to the sustainability and long-term success of the AI Arena protocol.
The AI Arena protocol showcases a robust and innovative gaming platform that effectively integrates AI with NFTs, offering users a unique experience in training and battling AI models. The key contracts, including FighterFarm.sol, RankedBattle.sol, and Neuron.sol, are well-structured and adhere to industry standards, ensuring a secure and functional ecosystem. However, the protocol faces systemic risks such as potential token inflation, alongside centralization risks stemming from the significant control wielded by owner and admin roles. To enhance the protocol's resilience and trustworthiness, it is recommended to implement decentralized governance mechanisms, introduce additional security practices, and consider further audits and bug bounty programs. These measures will help mitigate risks, optimize the gaming economy, and uphold the protocol's integrity.
65 hours
65 hours
#0 - c4-pre-sort
2024-02-25T20:32:23Z
raymondfam marked the issue as sufficient quality report
#1 - c4-judge
2024-03-19T08:14:31Z
HickupHH3 marked the issue as grade-b