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: 19/283
Findings: 4
Award: $268.27
π Selected for report: 0
π Solo Findings: 0
π Selected for report: Aamir
Also found by: 0rpse, 0x11singh99, 0x13, 0xAlix2, 0xAsen, 0xBinChook, 0xCiphky, 0xE1, 0xKowalski, 0xLogos, 0xWallSecurity, 0xaghas, 0xbranded, 0xlemon, 0xlyov, 0xpoor4ever, 0xprinc, 0xvj, ADM, Aymen0909, BARW, Bauchibred, Breeje, CodeWasp, DMoore, DeFiHackLabs, Draiakoo, Fulum, GhK3Ndf, Greed, Jorgect, Josh4324, Kalogerone, KmanOfficial, Krace, Limbooo, McToady, MidgarAudits, MrPotatoMagic, PedroZurdo, Pelz, Ryonen, SovaSlava, SpicyMeatball, Tendency, Timenov, ZanyBonzy, _eperezok, al88nsk, alexxander, alexzoid, aslanbek, blutorque, btk, cartlex_, cats, csanuragjain, deadrxsezzz, denzi_, devblixt, dimulski, djxploit, erosjohn, evmboi32, fnanni, grearlake, haxatron, hulkvision, immeas, israeladelaja, jaydhales, jesjupyter, jnforja, josephdara, juancito, kiqo, klau5, korok, krikolkk, ktg, kutugu, ladboy233, lil_eth, m4ttm, matejdb, merlinboii, n0kto, ni8mare, novamanbg, nuthan2x, oualidpro, pa6kuda, peter, petro_1912, pkqs90, pynschon, sandy, sashik_eth, shaflow2, shaka, sobieski, soliditywala, solmaxis69, stackachu, tallo, thank_you, tpiliposian, ubl4nk, visualbits, vnavascues, web3pwn, xchen1130, zhaojohnson
0.0037 USDC - $0.00
User can transfer nft gameItem, even it has transferable property with value False.
In contract GameItems there is function safeTransferFrom, which override function with the same name from ERC1155 contract and check restriction of transferable.
But standart contract from OZ ERC1155 has another function, which allow transfer tokens - safeBatchTransferFrom, and this function has not overrided by safeTransferFrom from GameItems contract.
So. for transfer nft, which restricted for transfer, user could just call GameItemsContract.safeBatchTransferFrom(userAddress,ReceiverAddress, nftid, amount, "");
Where nftid is array with nft id and amount is also array.
function testTransfer() public { _fundUserWith4kNeuronByTreasury(_ownerAddress); _gameItemsContract.mint(0, 2); //paying 2 $NRN for 2 batteries _gameItemsContract.adjustTransferability(0, false); uint[] memory nftid = new uint[](1); nftid[0] = 0; uint[] memory amount = new uint[](1); amount[0] = 1; _gameItemsContract.safeBatchTransferFrom(address(this),address(1), nftid, amount, ""); }
Manual review
Also override safeBatchTransferFrom function in GameItems contract
Token-Transfer
#0 - c4-pre-sort
2024-02-22T03:55:10Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T03:55:17Z
raymondfam marked the issue as duplicate of #18
#2 - c4-pre-sort
2024-02-26T00:28:09Z
raymondfam marked the issue as duplicate of #575
#3 - c4-judge
2024-03-05T04:47:39Z
HickupHH3 changed the severity to 3 (High Risk)
#4 - c4-judge
2024-03-05T04:53:25Z
HickupHH3 marked the issue as satisfactory
π Selected for report: nuthan2x
Also found by: 0xE1, 0xblackskull, 0xgrbr, 0xvj, Greed, McToady, MidgarAudits, PetarTolev, Sabit, SovaSlava, SpicyMeatball, Timenov, Tychai0s, _eperezok, alexxander, btk, c0pp3rscr3w3r, favelanky, jesjupyter, josephdara, juancito, klau5, kutugu, lil_eth, merlinboii, pynschon, sandy, shaflow2, zaevlad
29.1474 USDC - $29.15
The owner can only issue a role, there is no mechanism to revoke the role from the user
Contract have several functions, which allow owner grant roles to users (addMinter, addStaker, addSpender). But owner could not revoke these roles, because he is not have DEAULT_ADMIN_ROLE, which usually grants to owner in constructor. So, if owner try to call function from OZ Access contract revokeRole(), it will revert, because owner dont have role 0x0, which is admin of all roles by default
POC: // add this code to test/Neuron.t.sol
function testRevokeRole() public { address minter2 = makeAddr("secondMinter"); _neuronContract.addMinter(minter2); // will revert _neuronContract.revokeRole(_neuronContract.MINTER_ROLE(),minter2); }
Manual review
Add in constructor this line
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
Access Control
#0 - c4-pre-sort
2024-02-22T05:06:57Z
raymondfam marked the issue as insufficient quality report
#1 - c4-pre-sort
2024-02-22T05:07:04Z
raymondfam marked the issue as duplicate of #20
#2 - c4-judge
2024-03-05T07:34:09Z
HickupHH3 marked the issue as satisfactory
π Selected for report: ahmedaghadi
Also found by: 0x13, 0xAleko, 0xDetermination, 0xKowalski, 0xPluto, 0xRiO, 0xvj, AlexCzm, Avci, BARW, BigVeezus, Cryptor, DeFiHackLabs, Draiakoo, Fitro, Giorgio, GoSlang, Greed, Honour, Kalogerone, KmanOfficial, Krace, McToady, MidgarAudits, MrPotatoMagic, Nyxaris, ReadyPlayer2, Ryonen, SovaSlava, SpicyMeatball, VAD37, _eperezok, alexzoid, almurhasan, btk, cu5t0mpeo, deadrxsezzz, djxploit, dvrkzy, emrekocak, erosjohn, evmboi32, fnanni, grearlake, inzinko, jesjupyter, jesusrod15, josephdara, ke1caM, klau5, ktg, ladboy233, merlinboii, nuthan2x, peanuts, pipidu83, pontifex, radev_sw, sl1, sobieski, soliditywala, t0x1c, taner2344, vnavascues, y4y, yovchev_yoan, zaevlad
0.2347 USDC - $0.23
User could not claim tokens, if current round is big number, and before, user has not never call claim function.
if the user has never called the claimNRN() function and the current round is, for example, 1000, then the loop will go through 1000 times and calculate the user's reward for each loop. This will result in high gas consumption and cause the transaction to revert
uint32 lowerBound = numRoundsClaimed[msg.sender]; // <----- 0 for (uint32 currentRound = lowerBound; currentRound < roundId; currentRound++) { nrnDistribution = getNrnDistribution(currentRound); ...
Manual review
Create partial passage through the loop - pagination mechanism in claimNRN function, so user can specify from which round he would like iterate. But startRound should be greater than numRoundsClaimed[msg.sender]
DoS
#0 - c4-pre-sort
2024-02-25T02:25:10Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-25T02:25:35Z
raymondfam marked the issue as duplicate of #1541
#2 - c4-judge
2024-03-11T13:01:00Z
HickupHH3 marked the issue as duplicate of #216
#3 - c4-judge
2024-03-11T13:08:06Z
HickupHH3 changed the severity to 2 (Med Risk)
#4 - c4-judge
2024-03-12T02:44:16Z
HickupHH3 marked the issue as partial-50
#5 - c4-judge
2024-03-21T02:11:41Z
HickupHH3 marked the issue as satisfactory
π Selected for report: Timenov
Also found by: 0x11singh99, 0xblackskull, CodeWasp, MidgarAudits, MrPotatoMagic, Rolezn, Sabit, SovaSlava, andywer, btk, josephdara, lil_eth, merlinboii, sobieski, vnavascues
238.8948 USDC - $238.89
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L185-L188 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L139-L142
Owner could not disable old burning address
Contract has function, which grant privilege to burn tokens from other addresses. its function - setAllowedBurningAddresses. But if owner decide to change address, he could only grant privilege for new address, but he can not deprive privilege old address, because there is not such function, which set value False in mapping allowedBurningAddresses.
The same problem in FighterFarm.sol with staker role
function addStaker(address newStaker) external { require(msg.sender == _ownerAddress); hasStakerRole[newStaker] = true; }
Contract dont have function for remove staker
Manual review
Add new function
function delAllowedBurningAddresses(address newBurningAddress) public { require(isAdmin[msg.sender]); allowedBurningAddresses[newBurningAddress] = false; }
Access Control
#0 - c4-pre-sort
2024-02-22T19:27:26Z
raymondfam marked the issue as insufficient quality report
#1 - c4-pre-sort
2024-02-22T19:27:34Z
raymondfam marked the issue as duplicate of #47
#2 - c4-judge
2024-03-08T03:28:42Z
HickupHH3 marked the issue as satisfactory