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: 207/283
Findings: 3
Award: $2.10
๐ 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
Non-transferrable game items can still be transferred using batch transfer.
The safeTransferFrom function implements a check to see where the given game item(ERC1155 token) is transferrable using the following check:
function safeTransferFrom( address from, address to, uint256 tokenId, uint256 amount, bytes memory data ) public override(ERC1155) { require(allGameItemAttributes[tokenId].transferable); super.safeTransferFrom(from, to, tokenId, amount, data); }
It requires require(allGameItemAttributes[tokenId].transferable)
to be true to be transferred. However, this check is not implemented for safeBatchTransferFrom
that the ERC1155 standard uses. This allows users to transfer non-transferrable tokens. Thus, breaking the game's logic.
Manual review
Override the safeBatchTransferFrom function and include the above check for it as well.
Token-Transfer
#0 - c4-pre-sort
2024-02-22T04:12:48Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T04:12:55Z
raymondfam marked the issue as duplicate of #18
#2 - c4-pre-sort
2024-02-26T00:28:59Z
raymondfam marked the issue as duplicate of #575
#3 - c4-judge
2024-03-05T04:55:45Z
HickupHH3 marked the issue as satisfactory
๐ Selected for report: t0x1c
Also found by: 0rpse, 0xAadi, 0xBinChook, 0xCiphky, 0xDetermination, 14si2o_Flint, AC000123, Aamir, Abdessamed, Blank_Space, CodeWasp, DanielArmstrong, DarkTower, Draiakoo, Honour, Kalogerone, Krace, McToady, Merulez99, MidgarAudits, MrPotatoMagic, PedroZurdo, Silvermist, Tychai0s, VAD37, Velislav4o, VrONTg, WoolCentaur, YouCrossTheLineAlfie, ZanyBonzy, alexxander, aslanbek, btk, csanuragjain, d3e4, dimulski, djxploit, erosjohn, evmboi32, fnanni, forgebyola, forkforkdog, handsomegiraffe, immeas, israeladelaja, juancito, ktg, n0kto, neocrao, ni8mare, okolicodes, peanuts, petro_1912, shaflow2, shaka, swizz, ubermensch, ubl4nk, yotov721
2.0593 USDC - $2.06
The calculation of the staking factor is incorrect. Malicious users will always exploit it to stake less and win more points.
Consider users A and B with the same/similar ELO ratings and assume that they have no stake at risk.
Observe the way the staking factor is calculated:
function _getStakingFactor( uint256 tokenId, uint256 stakeAtRisk ) private view returns (uint256) { uint256 stakingFactor_ = FixedPointMathLib.sqrt( (amountStaked[tokenId] + stakeAtRisk) / 10**18 ); if (stakingFactor_ == 0) { stakingFactor_ = 1; } return stakingFactor_; }
We have assumed that both users have no stake at risk for the sake of this example.
Let's say that the amount staked by user A is 10**18 tokens, whereas user B has staked as little as 1 token. Hence, the stakingFactor_
for user A is 1 and for user B it is calculated as 0, but due to the conditional above it is set to 1 for user B as well.
Now, points are calculated in the following way:
points = stakingFactor[tokenId] * eloFactor;
Note that we have assumed that ELO ratings are the same for both users and since they have the same stakingFactor
, the points
calculated will also be the same for both users.
This means that a user with 1 token and another with 10**18 tokens staked will earn the same number of points, provided they have the same/similar ELO ratings. And when NRNs are distributed after a round, they are both likely to win the same amount of NRN tokens.
This would be a very unfair system and would not encourage users to stake more NRN tokens.
Manual review
Change the way the staking factor is calculated or ensure that a minimum amount of stake is needed to earn points.
Other
#0 - c4-pre-sort
2024-02-24T08:16:24Z
raymondfam marked the issue as insufficient quality report
#1 - c4-pre-sort
2024-02-24T08:16:34Z
raymondfam marked the issue as duplicate of #38
#2 - c4-judge
2024-03-07T02:49:49Z
HickupHH3 changed the severity to 2 (Med Risk)
#3 - c4-judge
2024-03-07T02:58:22Z
HickupHH3 changed the severity to 3 (High Risk)
#4 - c4-judge
2024-03-07T03:50:23Z
HickupHH3 marked the issue as satisfactory
๐ Selected for report: klau5
Also found by: 0rpse, 0xBinChook, 0xDetermination, 0xGreyWolf, 0xLogos, 0xWallSecurity, 0xaghas, 0xgrbr, 0xkaju, 0xlyov, AlexCzm, BARW, Blank_Space, BoRonGod, Daniel526, DanielArmstrong, Draiakoo, FloatingPragma, Giorgio, Greed, Jorgect, Matue, McToady, MidgarAudits, Nyxaris, PUSH0, PedroZurdo, Pelz, PoeAudits, Silvermist, SpicyMeatball, Tekken, Tricko, Tumelo_Crypto, VAD37, WoolCentaur, Zac, alexzoid, andywer, aslanbek, bgsmallerbear, cats, d3e4, desaperh, dimulski, dutra, erosjohn, evmboi32, favelanky, fnanni, forkforkdog, gesha17, givn, grearlake, haxatron, honey-k12, iamandreiski, immeas, juancito, kaveyjoe, ke1caM, kiqo, klau5, korok, lil_eth, lsaudit, n0kto, ni8mare, niser93, pa6kuda, peanuts, peter, shaka, sl1, soliditywala, solmaxis69, t0x1c, tallo, thank_you, tpiliposian, visualbits, vnavascues, web3pwn, yotov721
0.0352 USDC - $0.04
reRoll function is used to roll a fighter with random traits. But, these generated traits aren't random and thus can be gamed to generate characters with whatever traits a user requires.
Note the comment above the reRoll function. It talks about generating random traits.
/// @notice Rolls a new fighter with random traits. /// @param tokenId ID of the fighter being re-rolled. /// @param fighterType The fighter type. function reRoll(uint8 tokenId, uint8 fighterType) public {
For randomness it uses dna
which equals uint256(keccak256(abi.encode(msg.sender, tokenId, numRerolls[tokenId])))
. This value is then sent as an input to the _createFighterBase function which creates traits for the character associated with the token id. But, uint256(keccak256(abi.encode(msg.sender, tokenId, numRerolls[tokenId])))
will not generate truly random traits. It's a source of pseudo-randomness. A malicious user already knows the tokenId, numRerolls[tokenId] and can use any address to generate dna
values that they want. Then dna
value is used to generate traits like element and weight. So, a user can control what traits they want for their character.
Traits like element and weight are quite crucial in the game. This is what the documentation says about weight
:
๐๏ธ Weight - The relative composition of the metal alloy determines a fighterโs weight in the game. A fighterโs weight is the primary determinant of its other relative strength and weaknesses (i.e. all other battle attributes are a function of weight). Additionally, it is used to calculate how far the fighter moves when being knocked back.
If weight can be manipulated, then the game can be manipulated.
Manual review
Use a true source of randomness like Chainlink VRF.
Other
#0 - c4-pre-sort
2024-02-24T01:47:14Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-24T01:47:22Z
raymondfam marked the issue as duplicate of #53
#2 - c4-judge
2024-03-06T03:51:07Z
HickupHH3 marked the issue as satisfactory
#3 - c4-judge
2024-03-15T02:10:55Z
HickupHH3 changed the severity to 2 (Med Risk)
#4 - c4-judge
2024-03-22T04:21:17Z
HickupHH3 marked the issue as duplicate of #376