All three i_token.transfer() calls in Pot.sol ignore the return value. In claimCut(), the player's reward mapping is zeroed and remainingRewards decremented before the transfer. If the token's transfer() returns false without reverting, the player's reward is permanently erased with no tokens received.
The same pattern appears in closePot() for both the manager cut (line 55) and claimant surplus (line 59). Slither flags all three instances as unchecked-transfer.
Some ERC20 tokens (notably USDT on mainnet) return false on failure instead of reverting. With such tokens, a failed transfer silently passes while the contract's internal state already reflects the deduction.
Likelihood:
The README specifies "Standard ERC20 Tokens Only," and standard ERC20 implementations revert on failure. This reduces the likelihood since non-reverting tokens like USDT are technically out of scope. But any future token integration or fork that uses non-reverting tokens would be immediately vulnerable.
Impact:
A player permanently loses their entire reward. The mapping is zeroed, they are added to the claimants array (so they get surplus later), but the actual tokens never arrive. There is no way to re-claim.
No PoC provided because standard ERC20 tokens (in scope) revert on failure, making this scenario unreachable within the stated scope. The Slither detection confirms the code pattern is present.
Use OpenZeppelin's SafeERC20 wrapper, which handles both reverting and non-reverting tokens. This is a one-line change per call site and is standard practice for any ERC20 interaction.
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.