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: 239/283
Findings: 1
Award: $1.01
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: klau5
Also found by: 0xAlix2, 0xCiphky, 0xDetermination, 0xG0P1, 0xMosh, 0xabhay, 14si2o_Flint, AlexCzm, Aymen0909, CodeWasp, DanielArmstrong, FloatingPragma, Giorgio, JCN, Jorgect, Kalogerone, KmanOfficial, Kow, KupiaSec, McToady, SpicyMeatball, VAD37, WoolCentaur, ZanyBonzy, alexxander, alexzoid, almurhasan, blutorque, csanuragjain, denzi_, dipp, djxploit, evmboi32, handsomegiraffe, haxatron, immeas, jesjupyter, ke1caM, klau5, lanrebayode77, lil_eth, merlin, merlinboii, nuthan2x, peanuts, shaflow2, shaka, sl1, solmaxis69, stakog, swizz, t0x1c, tallo, ubermensch, vnavascues, yotov721
1.0089 USDC - $1.01
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L342 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L476-L478 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L491-L498
In the RankedBattle
smart contract, there is an updateBattleRecord
function designed to update the battle record for a fighter. If a fighter does not have any points for this round, NRNs are at risk of being lost. After a user loses all staked NRN tokens and they all transfer to the StakeAtRisk
smart contract, they can still participate in battles without risking the loss of points or NRN tokens when they lose.
When the updateBattleRecord
function is called, the internal function _addResultPoints
is invoked if the condition amountStaked[tokenId] + stakeAtRisk > 0
is met:
RankedBattle.sol#L341-L344
uint256 stakeAtRisk = _stakeAtRiskInstance.getStakeAtRisk(tokenId); if (amountStaked[tokenId] + stakeAtRisk > 0) { _addResultPoints( battleResult, tokenId, eloFactor, mergingPortion, fighterOwner ); }
The smart contract ensures that users cannot lose more NRNs than they have staked in their staking pool: RankedBattle.sol#L472-L478
} else if (battleResult == 2) { /// If the user lost the match /// Do not allow users to lose more NRNs than they have in their staking pool if (curStakeAtRisk > amountStaked[tokenId]) { curStakeAtRisk = amountStaked[tokenId]; }
So when the user has amountStaked
= 0, stakeAtRisk
> 0, then the current curStakeAtRisk
= 0, which means the user will not lose any NRN tokens:
RankedBattle.sol#L491-L498
} else { /// If the fighter does not have any points for this round, NRNs become at risk of being lost bool success = _neuronInstance.transfer(_stakeAtRiskAddress, curStakeAtRisk); if (success) { _stakeAtRiskInstance.updateAtRiskRecords(curStakeAtRisk, tokenId, fighterOwner); amountStaked[tokenId] -= curStakeAtRisk; } }
The following test case illustrates the scenario:
function testPlayMatchWithZeroAmountStake() public { address player = vm.addr(3); _mintFromMergingPool(player); _fundUserWith4kNeuronByTreasury(player); vm.prank(player); // stakes 1_000 NRN token _rankedBattleContract.stakeNRN(1_000 * 10 ** 18, 0); // loses battle and 1 NRN token vm.prank(address(_GAME_SERVER_ADDRESS)); _rankedBattleContract.updateBattleRecord(0, 50, 2, 1500, true); assertEq(_stakeAtRiskContract.getStakeAtRisk(0), 1 * 10 ** 18); // unstakes 999 NRN tokens vm.prank(player); _rankedBattleContract.unstakeNRN(999 * 10 ** 18, 0); // The user participates in battles while having amountStaked - 0, // meaning they are not risking anything vm.prank(address(_GAME_SERVER_ADDRESS)); _rankedBattleContract.updateBattleRecord(0, 50, 2, 1500, true); assertEq(_stakeAtRiskContract.getStakeAtRisk(0), 1 * 10 ** 18); }
The user will not lose points or NRN tokens when all their tokens are in the StakeAtRisk smart contract.
Manual
Consider not allowing the user to participate in a battle when amountStaked = 0
:
function updateBattleRecord( uint256 tokenId, uint256 mergingPortion, uint8 battleResult, uint256 eloFactor, bool initiatorBool ) external { // code uint256 stakeAtRisk = _stakeAtRiskInstance.getStakeAtRisk(tokenId); - if (amountStaked[tokenId] + stakeAtRisk > 0) { + if (amountStaked[tokenId] != 0 && amountStaked[tokenId] + stakeAtRisk > 0) { _addResultPoints( battleResult, tokenId, eloFactor, mergingPortion, fighterOwner ); } // code }
Invalid Validation
#0 - c4-pre-sort
2024-02-22T16:50:32Z
raymondfam marked the issue as insufficient quality report
#1 - c4-pre-sort
2024-02-22T16:50:40Z
raymondfam marked the issue as duplicate of #833
#2 - c4-pre-sort
2024-02-24T05:28:18Z
raymondfam marked the issue as sufficient quality report
#3 - c4-judge
2024-03-13T11:32:38Z
HickupHH3 marked the issue as duplicate of #1641
#4 - c4-judge
2024-03-13T14:17:55Z
HickupHH3 marked the issue as satisfactory