Summary
The battlesWon
from the struct IOneShot::RapperStats
is never updated.
Vulnerability Details
The OneShot::updateRapperStats
function is responsible for updating the struct RapperStats
. This function can be called only from the Street
contract:
function updateRapperStats(
uint256 tokenId,
bool weakKnees,
bool heavyArms,
bool spaghettiSweater,
bool calmAndReady,
uint256 battlesWon
) public onlyStreetContract {
RapperStats storage metadata = rapperStats[tokenId];
metadata.weakKnees = weakKnees;
metadata.heavyArms = heavyArms;
metadata.spaghettiSweater = spaghettiSweater;
metadata.calmAndReady = calmAndReady;
metadata.battlesWon = battlesWon;
}
The Streets
contract calls the OneShot::updateRapperStats
in unstake
function and updates some of the parameters of the struct, but the battlesWon
is not one of them:
function unstake(uint256 tokenId) external {
require(stakes[tokenId].owner == msg.sender, "Not the token owner");
uint256 stakedDuration = block.timestamp - stakes[tokenId].startTime;
uint256 daysStaked = stakedDuration / 1 days;
IOneShot.RapperStats memory stakedRapperStats = oneShotContract.getRapperStats(tokenId);
emit Unstaked(msg.sender, tokenId, stakedDuration);
delete stakes[tokenId];
if (daysStaked >= 1) {
stakedRapperStats.weakKnees = false;
credContract.mint(msg.sender, 1);
}
if (daysStaked >= 2) {
stakedRapperStats.heavyArms = false;
credContract.mint(msg.sender, 1);
}
if (daysStaked >= 3) {
stakedRapperStats.spaghettiSweater = false;
credContract.mint(msg.sender, 1);
}
if (daysStaked >= 4) {
stakedRapperStats.calmAndReady = true;
credContract.mint(msg.sender, 1);
}
if (daysStaked >= 1) {
oneShotContract.updateRapperStats(
tokenId,
stakedRapperStats.weakKnees,
stakedRapperStats.heavyArms,
stakedRapperStats.spaghettiSweater,
stakedRapperStats.calmAndReady,
stakedRapperStats.battlesWon
);
}
Impact
In the README
is said:
Users mint a rapper that begins with all the flaws and self-doubt we all experience. NFT Mints with the following properties:
weakKnees - True
heavyArms - True
spaghettiSweater - True
calmandReady - False
battlesWon - 0
The only way to improve these stats is by staking in the Streets.sol
But the Streets
contract doesn't update the battlesWon
. And the battlesWon
will always be 0
regardless how many wins has the rapper.
Tools Used
Manual Review
Recommendations
It is logical the battlesWon
from struct RapperStats
to be updated in the RapBattle::_battle
function when someone wins a battle.
I know it is a design choice the OneShot::updateRapperStats
to be updated only from the Streets
contract. But consider the possibility for updating the RapperStats
also from RapBattle
contract in the _battle
function or remove the battlesWon
from RapperStats
struct. It is not used and not updated.