SMART CONTRACTS, DEFI & WEB3 SECURITY - Chapter 10, Exercise 1 Solution ========================================================== A Locking Flag vs. Checks-Effects-Interactions PROBLEM ------- A colleague proposes fixing the reentrancy vulnerability by adding a require(!inProgress) "locking" flag instead of reordering the three lines into checks-effects-interactions order. Explain whether this alternative fix would genuinely work, and which approach this chapter's own fix actually used. SOLUTION -------- This chapter's own fix used checks-effects-interactions: the balance is reduced (the "effect") before the external token.transfer() call (the "interaction") ever happens, so a reentrant call sees an already-reduced balance and cannot withdraw a second time. A LOCKING FLAG - AND WHY IT CAN ALSO WORK A locking flag is a genuinely real, alternative defense against reentrancy, and it is not a wrong idea. The pattern works by setting a boolean flag (something like inProgress = true) before the external call, checking that flag with a require statement at the very start of the function, and resetting it to false only after the external call completes. If a malicious contract tries to call withdraw() again while the original call is still executing, the require(!inProgress) check would fail immediately, since the flag is still set to true from the outer, still-executing call. WHY BOTH ARE REAL, VALID APPROACHES Both techniques solve the same underlying problem from different angles. Checks-effects-interactions prevents the exploit by making sure there is nothing left worth re-entering for - the balance is already correctly updated before the vulnerable call happens. A locking flag instead prevents the exploit by directly blocking any reentrant call from executing at all, regardless of what state has or hasn't been updated yet. This exact locking-flag pattern is, in fact, the real underlying mechanism behind widely used reentrancy-guard utilities in professional Solidity development. WHY CHECKS-EFFECTS-INTERACTIONS WAS USED HERE This chapter's own fix used checks-effects-interactions specifically because it requires no new state variable at all - simply reordering three lines that already existed. A locking flag is an equally valid fix, but it needs an additional storage variable and a small amount of extra gas cost to set and reset it, which checks-effects-interactions avoids entirely for a function this simple. ANSWER: A require(!inProgress) locking flag would genuinely work as a fix - it is a real, valid reentrancy defense that blocks any reentrant call from executing while the outer call is still in progress, and is in fact the same underlying mechanism behind common reentrancy-guard utilities. This chapter's own fix instead used checks-effects- interactions, reordering the existing three lines so the balance is reduced before the external transfer() call happens, which closes the same vulnerability without needing any new state variable at all. ---- WHY THIS WORKS AS AN ANSWER It correctly validates the proposed alternative rather than dismissing it, explains the real mechanism behind why a locking flag would also work, and accurately identifies which specific technique this chapter's own fix actually used and why it was the simpler choice for this function.