Last Man Standing

First Flight #45
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

Manual Reentrancy Guard Used Instead of OpenZeppelin’s Trusted `ReentrancyGuard`

Root Cause

The developer opted for a manual boolean-based locking mechanism instead of using OpenZeppelin’s standardized and audited ReentrancyGuard, which is the industry norm.


Description

The contract implements its own reentrancy guard by using a _locked boolean flag, set manually in the claimThrone function:

function claimThrone() external payable gameNotEnded {
require(!_locked, "Reentrant call");
_locked = true;
// game logic here...
_locked = false;
}

While this may work in straightforward scenarios, manual reentrancy locks:

  • Are more error-prone due to inconsistent state handling.

  • Can be accidentally skipped or misused.

  • Lack the confidence of an audited implementation.

Instead, OpenZeppelin’s ReentrancyGuard is a rigorously tested and gas-optimized library trusted across thousands of production-grade contracts.


Risk

  • Impact: Low

  • The custom _locked boolean does prevent reentrancy under normal usage. However, relying on hand-rolled logic increases maintenance burden and introduces potential for error.

  • Likelihood: Low

  • The current implementation appears safe, but deviates from best practices and lacks audit provenance.

Proof of Concept

While no reentrancy bug is present currently, a subtle mistake like missing the _locked = false on all revert paths would lead to denial-of-service. Similarly, nested external calls without checks could create future reentrancy vectors if logic expands.

Manual example:

_locked = true;
externalContract.callThatReverts(); // if this reverts and unlock isn't after it, contract stays locked
_locked = false;

Recommended Mitigation

Use OpenZeppelin’s built-in ReentrancyGuard modifier for robust and battle-tested protection:

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract Game is ReentrancyGuard {
function claimThrone() external payable nonReentrant {
// safe from reentrancy
}
}

Benefits:

  • Standardized and audited.

  • Less room for human error.

  • Easier for auditors and reviewers to trust.


References


Updates

Appeal created

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
thesandf Submitter
about 2 months ago
inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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