pragma solidity 0.8.20;
import {ERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
contract ERC20Weird is ERC20 {
uint256 public transferFeePercent = 100;
address public feeCollector;
mapping(address => bool) public isBlocked;
constructor(string memory name, string memory symbol, address initialAccount, uint256 initialBalance)
payable
ERC20(name, symbol)
{
_mint(initialAccount, initialBalance);
feeCollector = initialAccount;
}
function decimals() public pure override returns (uint8) {
return 6;
}
function mint(address account, uint256 amount) public {
_mint(account, amount);
}
function burn(address account, uint256 amount) public {
_burn(account, amount);
}
function transferInternal(address from, address to, uint256 value) public {
_transfer(from, to, value);
}
function approveInternal(address owner, address spender, uint256 value) public {
_approve(owner, spender, value);
}
function addToBlocklist(address account) public {
isBlocked[account] = true;
}
function removeFromBlocklist(address account) public {
isBlocked[account] = false;
}
function setTransferFee(uint256 _feePercent) public {
require(_feePercent <= 1000, "Fee too high");
transferFeePercent = _feePercent;
}
function setFeeCollector(address _feeCollector) public {
feeCollector = _feeCollector;
}
function transfer(address to, uint256 amount) public override returns (bool) {
address owner = _msgSender();
require(!isBlocked[owner], "Sender is blocked");
require(!isBlocked[to], "Recipient is blocked");
if (transferFeePercent > 0 && owner != feeCollector && to != feeCollector) {
uint256 fee = (amount * transferFeePercent) / 10000;
uint256 amountAfterFee = amount - fee;
_transfer(owner, feeCollector, fee);
_transfer(owner, to, amountAfterFee);
} else {
_transfer(owner, to, amount);
}
return true;
}
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
require(!isBlocked[from], "Sender is blocked");
require(!isBlocked[to], "Recipient is blocked");
if (transferFeePercent > 0 && from != feeCollector && to != feeCollector) {
uint256 fee = (amount * transferFeePercent) / 10000;
uint256 amountAfterFee = amount - fee;
_transfer(from, feeCollector, fee);
_transfer(from, to, amountAfterFee);
} else {
_transfer(from, to, amount);
}
return true;
}
function balanceOf(address account) public view override returns (uint256) {
return super.balanceOf(account);
}
}
contract TestMyCut is Test {
address conMan;
address player1 = makeAddr("player1");
address player2 = makeAddr("player2");
address[] players = [player1, player2];
uint256 public constant STARTING_USER_BALANCE = 1000 ether;
ERC20Mock weth;
ERC20Weird tokenX;
address contest;
address[] totalContests;
uint256[] rewards = [3, 1];
address user = makeAddr("user");
uint256 totalRewards = 4;
uint256[] rewardsArr = [3, 3];
uint256[] rewardsArr1 = [50, 50];
function setUp() public {
vm.startPrank(user);
conMan = address(new ContestManager());
weth = new ERC20Mock("WETH", "WETH", msg.sender, 1000e8);
tokenX = new ERC20Weird("USDC", "USDC", msg.sender, 10_000e6);
console.log("User Address: ", user);
vm.stopPrank();
}
modifier mintAndApproveTokens() {
console.log("Minting tokens to: ", user);
vm.startPrank(user);
ERC20Mock(weth).mint(user, STARTING_USER_BALANCE);
ERC20Mock(weth).approve(conMan, STARTING_USER_BALANCE);
ERC20Weird(tokenX).mint(user, 10_000e6);
ERC20Weird(tokenX).approve(conMan, 10_000e6);
console.log("Approved tokens to: ", address(conMan));
vm.stopPrank();
_;
}
function test_blocklistedUserDoS() public mintAndApproveTokens {
address[] memory addresses = new address[](10);
uint256[] memory nums = new uint256[](10);
for (uint256 i = 0; i < 10; i++) {
addresses[i] = address(uint160(i + 1));
nums[i] = 50;
}
vm.startPrank(user);
contest = ContestManager(conMan).createContest(addresses, nums, IERC20(ERC20Weird(tokenX)), 10_000e6);
ContestManager(conMan).fundContest(0);
vm.stopPrank();
assertEq(9900e6, ERC20Weird(tokenX).balanceOf(contest));
for (uint256 i = 0; i < 7; i++) {
vm.prank(addresses[i]);
Pot(contest).claimCut();
}
ERC20Weird(tokenX).addToBlocklist(addresses[0]);
vm.warp(91 days);
vm.prank(user);
vm.expectRevert();
ContestManager(conMan).closeContest(contest);
}
}
Introduce a mapping in the Pot contract where that mapping is going to store address -> bool -> uint256 amount respectively -> user address -> isClaimingAdditionalRewards -> amount . And then introduce a new function that is going to be called by the users and if they are in the mapping and have additional rewards to be able to pull them from the contract