Sparkn

CodeFox Inc.
DeFiFoundryProxy
15,000 USDC
View results
Submission Details
Severity: low
Valid

Commission fees and remaining tokens can get stucked in contract if stadium address is blacklisted.

Summary

The Comission fee and remaining tokens can get stucked in the contract if stadium address gets blacklisted. Additonally, since the function _commisionTransfer is included inside the _distribute function, this will end with a revert because transfering this fee/remaining assets is the last step of the distribution process.

Vulnerability Details

The issue arises when the stadium address is unaware of being included in a blocklist, before receiving the fee and/or remainings. Neither the Distributor.sol contract nor the ProxyFactory.sol currently incorporate proper verifications to mitigate this specific blocklist scenario. The consequence of this is that the primary task of _comissionTransfer (avoid dust remaining) will fail, and moreover since this function is also called inside the _distribute function, it will also produce a failure.

The following PoC can illustrate the issue. For simulating the block, we will use the the HelperContract.t.sol by simply putting the stadium address to 0 declared in the test contract, (for simplifying the scenario). In this way using the testIfAllConditionsMetThenUsdcSendingCallShouldSuceed, we will see that while most of the contest process is correctly parsed, the last part corresponding to the distribution of the comission fee will fail as the stadium address is invalid.

// users
address public stadiumAddress = address(0);
address public factoryAdmin = makeAddr("factoryAdmin");
address public tokenMinter = makeAddr("tokenMinter");
address public organizer = address(11);
function testIfAllConditionsMetThenUsdcSendingCallShouldSuceed()
public
setUpContestForNameAndSentAmountToken("James", jpycv2Address, 10000 ether)
{
// Code chunk not displayed
//....
// after this, token should be distributed correctly as expected
assertEq(MockERC20(usdcAddress).balanceOf(address(user1)), 900 ether);
assertEq(MockERC20(usdcAddress).balanceOf(address(user2)), 50 ether);
(, , uint256 commissionFee, ) =
proxyWithDistributorLogic.getConstants();
assertEq(commissionFee, 500);
assertEq(MockERC20(usdcAddress).balanceOf(stadiumAddress), 50 ether);
}

*** The comission fee is stucked inside the contract as we can verify using the getConstants() method.

├─ [563] MockERC20::balanceOf(user1: [0x000000000000000000000000000000000000000E]) [staticcall]
│ └─ ← 900000000000000000000 [9e20]
├─ [563] MockERC20::balanceOf(user2: [0x000000000000000000000000000000000000000F]) [staticcall]
│ └─ ← 50000000000000000000 [5e19]
├─ [502] 0x9824278B4b41B8f00c96f05BA590Af1a5cE0E326::getConstants() [staticcall]
│ ├─ [249] Distributor::getConstants() [delegatecall]
│ │ └─ ← ProxyFactory: [0x5FbDB2315678afecb367f032d93F642f64180aa3], stadium: [0xFa6523E66a411fC3d12656507877B8cbf1E39aC0], 500, 1
│ └─ ← ProxyFactory: [0x5FbDB2315678afecb367f032d93F642f64180aa3], stadium: [0xFa6523E66a411fC3d12656507877B8cbf1E39aC0], 500, 1
├─ [2563] MockERC20::balanceOf(0x0000000000000000000000000000000000000000) [staticcall]
│ └─ ← 0
├─ emit log(: Error: a == b not satisfied [uint])
├─ emit log_named_uint(key: Left, val: 0)
├─ emit log_named_uint(key: Right, val: 50000000000000000000 [5e19])
├─ [0] VM::store(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 0x6661696c65640000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000001)
│ └─ ← ()
└─ ← ()

Impact

The comission fee and all remaining tokens can get stuck in the contract. Additionally the _distribute function will fail as the last step where comissions are transfered will not work.

Tools Used

Manual Review

Recommendations

Implement the necessary checks for the possible blocklist of the stadium address that can prevent this failure.

Support

FAQs

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