The main concept here is if the address of any winner is blacklisted by token contract then it can not receive funds and reverting the entire transaction. Below is a proof of concept how a blacklisted address can cause a temporary DOS and reverting the whole transaction each time.
const { expect } = require("chai");
const { ethers } = require("hardhat");
const contestId =
"0x7465737400000000000000000000000000000000000000000000000000000000";
const randomBytes =
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
async function getTime(days) {
const blockNumber = await ethers.provider.getBlockNumber();
const block = await ethers.provider.getBlock(blockNumber);
const currentTimestamp = block.timestamp;
const futureTimestamp = currentTimestamp + days * 86400;
return futureTimestamp;
}
async function deployMockToken(acc) {
const testToken = await ethers.getContractFactory("MockERC20");
const connectToken = testToken.connect(acc);
const MockERC20 = await connectToken.deploy();
return MockERC20;
}
async function getSomeTokens(acc, token, amount) {
await token.connect(acc).mint(amount);
}
async function deployImplementation(_factoryAddress, _stadiumAddress) {
const distributor = await ethers.getContractFactory("Distributor");
const Distributor = await distributor.deploy(
_factoryAddress,
_stadiumAddress
);
return Distributor;
}
describe("CodeHawks", function () {
it("SPARKN", async function () {
const [
ERC20Deployer,
stadiumAddress,
factoryDeployer,
organizer,
winner,
blacklistedWinner,
] = await ethers.getSigners();
const USDT = await deployMockToken(ERC20Deployer);
expect(await USDT.owner()).to.equal(ERC20Deployer.address);
await USDT.connect(ERC20Deployer).addToBlacklist(blacklistedWinner);
expect(await USDT.isBlacklisted(blacklistedWinner)).to.equal(true);
expect(await USDT.isBlacklisted(winner)).to.equal(false);
await getSomeTokens(organizer, USDT, 10000000);
const factory = await ethers.getContractFactory("ProxyFactory");
const connectedFactory = factory.connect(factoryDeployer);
const ProxyFactory = await connectedFactory.deploy([USDT]);
const Distributor = await deployImplementation(
ProxyFactory.target,
stadiumAddress
);
const getData = await ethers.getContractFactory("delegateCall");
const delegateCall = await getData.deploy();
const delegateCallData = await delegateCall.getCallData(
USDT,
[winner, blacklistedWinner],
[5000, 4500],
randomBytes
);
const closeTime = await getTime(10);
await ProxyFactory.connect(factoryDeployer).setContest(
organizer,
contestId,
closeTime,
Distributor.target
);
const saltofContest = await ProxyFactory._calculateSalt(
organizer,
contestId,
Distributor.target
);
const proxy_address = await ProxyFactory.getProxyAddress(
saltofContest,
Distributor.target
);
await USDT.connect(organizer).transfer(proxy_address, 100000);
try {
await ProxyFactory.connect(organizer).deployProxyAndDistribute(
contestId,
Distributor.target,
delegateCallData
);
} catch (error) {
console.log(error);
}
});
});
In conclusion, this issue can not brick the system entirely, and can not permanently stop organizer to distribute rewards to the winners. However, it may still cause a temporary DoS.