Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: low
Valid

`battlesWon` statistics in the `OneShot::RapperStats` Struct is Not Updated After Winning a Battle

Summary

battlesWon is an element of the OneShot::RapperStats structure, a piece of the NFT's metadata, and is supposed to track how many battles has been won with a given rapper NFT. However, this element is never updated in the protocol, it remains 0 even if battles are won with an NFT.

Impact

The metadata of the NFTs will be incorrect. Specifically, the battlesWon statistics will not correctly reflect the number of battles an NFT has previously won.

Proof of Code

Insert the following piece of code in OneShotTest.t.sol:

function test_battlesWonNotUpdated() public twoSkilledRappers {
vm.startPrank(user);
uint256 initialuserBalance = cred.balanceOf(user);
cred.approve(address(rapBattle), initialuserBalance);
oneShot.approve(address(rapBattle), 0);
rapBattle.goOnStageOrBattle(0, initialuserBalance);
vm.stopPrank();
vm.startPrank(challenger);
cred.approve(address(rapBattle), initialuserBalance);
// oneShot.approve(address(rapBattle), 1);
vm.recordLogs();
rapBattle.goOnStageOrBattle(1, initialuserBalance);
vm.stopPrank();
Vm.Log[] memory entries_2 = vm.getRecordedLogs();
address winner = address(uint160(uint256(entries_2[0].topics[2])));
assertEq(winner, challenger); // challenger won with NFT ID = 1
assertEq(oneShot.ownerOf(1), challenger);
stats = oneShot.getRapperStats(1);
assertEq(stats.battlesWon, 0);
}

and run it by executing forge test --mt test_battlesWonNotUpdated.

Output:

Running 1 test for test/OneShotTest.t.sol:RapBattleTest
[PASS] test_battlesWonNotUpdated() (gas: 640173)
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 16.50ms

Tools Used

Manual reivew, Foundry.

Recommendations

There are 2 possible solutions:

  • remove this battlesWon element from the OneShot::RapperStats structure, and update the rest of the codebase accordingly. (Especially since it seems to be only a vanity metric that has no effect anywhere.), or

  • update the battlesWon element after every battle as follows:

function _battle(uint256 _tokenId, uint256 _credBet) internal {
address _defender = defender;
require(defenderBet == _credBet, "RapBattle: Bet amounts do not match");
uint256 defenderRapperSkill = getRapperSkill(defenderTokenId);
uint256 challengerRapperSkill = getRapperSkill(_tokenId);
uint256 totalBattleSkill = defenderRapperSkill + challengerRapperSkill;
uint256 totalPrize = defenderBet + _credBet;
uint256 random =
uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender))) % totalBattleSkill;
// Reset the defender
defender = address(0);
emit Battle(msg.sender, _tokenId, random < defenderRapperSkill ? _defender : msg.sender);
// If random <= defenderRapperSkill -> defenderRapperSkill wins, otherwise they lose
if (random <= defenderRapperSkill) {
// We give them the money the defender deposited, and the challenger's bet
credToken.transfer(_defender, defenderBet);
credToken.transferFrom(msg.sender, _defender, _credBet);
+ IOneShot.RapperStats memory stats = oneShotNft.getRapperStats(defenderTokenId);
+ uint256 updatedBattlesWon = stats.battlesWon + 1;
+ oneShotNft.updateRapperStats(defenderTokenId, stats.weakKnees, stats.heavyArms, stats.spaghettiSweater, stats.calmAndReady, updatedBattlesWon);
} else {
// Otherwise, since the challenger never sent us the money, we just give the money in the contract
credToken.transfer(msg.sender, _credBet);
+ IOneShot.RapperStats memory stats = oneShotNft.getRapperStats(_tokenId);
+ uint256 updatedBattlesWon = stats.battlesWon + 1;
+ oneShotNft.updateRapperStats(_tokenId, stats.weakKnees, stats.heavyArms, stats.spaghettiSweater, stats.calmAndReady, updatedBattlesWon);
}
totalPrize = 0;
// Return the defender's NFT
oneShotNft.transferFrom(address(this), _defender, defenderTokenId);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

`battlesWon` is never updated

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.