In the `Streets::Unstake()` function, the Staked Rapper NFTs must only earn
1 Cred ERC20/day staked up to 4 maximum.
```
diff
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;
// Assuming RapBattle contract has a function to update metadata properties
IOneShot.RapperStats memory stakedRapperStats = oneShotContract.getRapperStats(tokenId);
emit Unstaked(msg.sender, tokenId, stakedDuration);
delete stakes[tokenId]; // Clear staking info
// Apply changes based on the days staked
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);
}
// Only call the update function if the token was staked for at least one day
if (daysStaked >= 1) {
oneShotContract.updateRapperStats(
tokenId,
stakedRapperStats.weakKnees,
stakedRapperStats.heavyArms,
stakedRapperStats.spaghettiSweater,
stakedRapperStats.calmAndReady,
stakedRapperStats.battlesWon
);
}
// Continue with unstaking logic (e.g., transferring the token back to the owner)
oneShotContract.transferFrom(address(this), msg.sender, tokenId);
}
```
The last if() condition, in which we change the value of the `RapperStats::calmAndReady` attribute,
must check that after 4 days Staked Rapper NFTs can't longer mine CREDs.
For that, if the condition specifies that `daysStaked>=4`, as is currently the case,
this means that even after 4 days, i.e. the 5th or 6th day, CREDs can still be
mined by the Staked Rapper NFTs.
As long as Rapper NFTs is stake, it can continue to earn CREDs infinitely even after 4 days.
For example, this test, run 10 days after a stake, passes without error.
```
// Test rapper stats are updated when a rapper is staked for at least one day
function testRapperStatsUpdatedWhenRapperStakedForOneDay() public mintRapper {
vm.startPrank(user);
oneShot.approve(address(streets), 0);
streets.stake(0);
vm.stopPrank();
@=> vm.warp(10 days + 1);
vm.startPrank(user);
streets.unstake(0);
stats = oneShot.getRapperStats(0);
assert(stats.weakKnees == false);
assert(stats.heavyArms == false);
assert(stats.spaghettiSweater == false);
assert(stats.calmAndReady == true);
assert(stats.battlesWon == 0);
}
```
-Foundry
-fuzz test
The condition `daysStaked>=4` must be replaced by the condition `daysStaked<=4 in
the function `Streets::unstake()`
```diff
// Unstake tokens by transferring them back to their owner
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;
// Assuming RapBattle contract has a function to update metadata properties
IOneShot.RapperStats memory stakedRapperStats = oneShotContract.getRapperStats(tokenId);
emit Unstaked(msg.sender, tokenId, stakedDuration);
delete stakes[tokenId]; // Clear staking info
// Apply changes based on the days staked
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) {
+ if (daysStaked <= 4) {
stakedRapperStats.calmAndReady = true;
credContract.mint(msg.sender, 1);
}
// Only call the update function if the token was staked for at least one day
if (daysStaked >= 1) {
oneShotContract.updateRapperStats(
tokenId,
stakedRapperStats.weakKnees,
stakedRapperStats.heavyArms,
stakedRapperStats.spaghettiSweater,
stakedRapperStats.calmAndReady,
stakedRapperStats.battlesWon
);
}
// Continue with unstaking logic (e.g., transferring the token back to the owner)
oneShotContract.transferFrom(address(this), msg.sender, tokenId);
}
```
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.