Root Cause
In ContestManager.sol lines 42-44, fundContest() checks the owner's token balance but then uses transferFrom() which requires allowance:
Misleading error message: Owner sees "InsufficientFunds" but actually has sufficient balance
Confusion: Owner checks balance, sees enough tokens, but transaction reverts
Debugging time wasted: Owner doesn't realize they need to approve() first
Functionality works if allowance is set correctly
The fundContest() function checks the owner's token balance but then uses transferFrom() which requires allowance. If the owner has sufficient balance but hasn't approved the ContestManager, the balance check passes but transferFrom reverts with a misleading error.
Likelihood:
Medium - UX issue causing confusion. Doesn't lose funds but creates poor developer/user experience.
Impact:
Misleading error message: Owner sees "InsufficientFunds" but actually has sufficient balance
Confusion: Owner checks balance, sees enough tokens, but transaction reverts
Debugging time wasted: Owner doesn't realize they need to approve() first
Functionality works if allowance is set correctly
Before this goes out, I'd reframe the root cause from "misleading error message" to: the balance check is a redundant no-op against compliant tokens, and the unchecked transferFrom return value causes a silent, non-reverting funding failure against non-compliant tokens. That's a stronger, verifiable claim than the current narrative, and it changes the Impact table — this isn't purely a UX annoyance anymore, since a contest can end up in a "funded" state with an empty pot and no error to flag it. Severity is still your call, but I'd expect this to at least stay Medium and arguably push toward the fund-integrity side rather than pure UX.
The following Foundry test reproduces the vulnerability end-to-end. Save it as test/M02_FundContest_PoC.t.sol.
▶️ How to Run
The best-practice fix is — wrap the transfer with OpenZeppelin's SafeERC20.safeTransferFrom and remove the manual balance check entirely, letting the ERC-20 implementation surface the precise failure reason:
safeTransferFrom reverts with a descriptive error (ERC20InsufficientAllowance or ERC20InsufficientBalance) — exactly matching what the contract is actually checking.
It also safely handles non-standard ERC-20s that return false from transferFrom instead of reverting.
Removing the redundant balanceOf check eliminates the misleading custom error path entirely.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.