Challenge - 5 Problems
Checks-Effects-Interactions Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate2:00remaining
Output of a simple withdrawal function using Checks-Effects-Interactions
What is the output when calling
withdraw(50) on this contract if the initial balance is 100?Blockchain / Solidity
contract SimpleBank {
mapping(address => uint) public balances;
constructor() {
balances[msg.sender] = 100;
}
function withdraw(uint amount) public returns (string memory) {
require(balances[msg.sender] >= amount, "Insufficient balance"); // Check
balances[msg.sender] -= amount; // Effect
(bool success, ) = msg.sender.call{value: amount}(""); // Interaction
require(success, "Transfer failed");
return "Withdrawal successful";
}
receive() external payable {}
}Attempts:
2 left
💡 Hint
Think about the order: check balance, update balance, then send funds.
✗ Incorrect
The function first checks if the sender has enough balance, then reduces it, and finally sends the amount. Since the initial balance is 100 and withdrawal is 50, all steps succeed and the function returns "Withdrawal successful".
❓ Predict Output
intermediate2:00remaining
Effect of changing order in Checks-Effects-Interactions
What happens if the
withdraw function sends funds before updating the balance?Blockchain / Solidity
function withdraw(uint amount) public returns (string memory) {
require(balances[msg.sender] >= amount, "Insufficient balance"); // Check
(bool success, ) = msg.sender.call{value: amount}(""); // Interaction
require(success, "Transfer failed");
balances[msg.sender] -= amount; // Effect
return "Withdrawal successful";
}Attempts:
2 left
💡 Hint
Consider what happens if the receiver calls back into withdraw before balance changes.
✗ Incorrect
Sending funds before updating balance allows the receiver to call withdraw again before balance is reduced, causing multiple withdrawals and a reentrancy attack.
🔧 Debug
advanced2:30remaining
Identify the bug in this contract violating Checks-Effects-Interactions
Which line causes a security risk violating the Checks-Effects-Interactions pattern?
Blockchain / Solidity
contract Vulnerable {
mapping(address => uint) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "Failed to send Ether");
balances[msg.sender] -= amount;
}
}Attempts:
2 left
💡 Hint
Look for interaction before effect.
✗ Incorrect
The call to send Ether happens before updating the balance, allowing reentrancy attacks. The effect (balance update) should happen before interaction.
🧠 Conceptual
advanced1:30remaining
Why is Checks-Effects-Interactions pattern important?
Which statement best explains the main reason for using the Checks-Effects-Interactions pattern in smart contracts?
Attempts:
2 left
💡 Hint
Think about what kind of attack this pattern helps avoid.
✗ Incorrect
Updating the contract's state before making external calls prevents attackers from exploiting reentrancy by calling back into the contract before state changes.
🚀 Application
expert3:00remaining
How many times can a reentrant call withdraw funds in this contract?
Given this contract, how many times can a malicious contract reenter and withdraw funds before balance updates?
Blockchain / Solidity
contract ReentrancyExample {
mapping(address => uint) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "Failed to send Ether");
balances[msg.sender] -= amount;
}
}Attempts:
2 left
💡 Hint
Consider that balance is updated after sending funds.
✗ Incorrect
Because balance is updated after sending funds, the attacker can reenter multiple times withdrawing repeatedly until funds or gas run out.