When a function call fails mid-function, the contract may continue execution without rolling back previous changes, leading to partial, unintended state changes.
Game
Imagine a contract that performs a series of critical operations, one of which involves an external call to another contract. What is missing here?
// SPDX-License-Identifier: MIT// Open me in VSCode and really think before opening the hints!// Add @audit tags wherever suspicious// Go to the solidity docs to complete missing knowledge of what's happening here// Solve by drafting a fix!pragmasolidity ^0.8.0;interface IExternalContract {functiondoAction() externalreturns (bool);}contract PartialExecutionGame { IExternalContract public externalContract;uint256public balance;constructor(address_externalContract) { externalContract =IExternalContract(_externalContract); }// Function that performs a sequence of operations, including an unchecked external callfunctionexecuteSequence(uint256 amount) public { balance += amount; // Step 1: Increase balancebool success = externalContract.doAction(); // Step 2: External callif (!success) { balance -= amount; // Attempt to revert manually, but this is partial } }}
Consider what would happen if doAction fails.
Is the balance effectively rolled back, and does the contract return to a fully consistent state?
A more reliable approach might involve enforcing that all steps succeed or none at all, using a mechanism to revert the entire transaction on failure.
functionexecuteSequence(uint256 amount) public { balance += amount; // Step 1: Increase balancebool success = externalContract.doAction(); require(success,"External action failed"); // Fix: Revert the entire transaction on failure}