Bird
Raised Fist0
Blockchain / Solidityprogramming~20 mins

Checks-Effects-Interactions pattern in Blockchain / Solidity - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Checks-Effects-Interactions Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2: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 {}
}
ARevert with "Transfer failed"
BRevert with "Insufficient balance"
C"Withdrawal successful"
DNo output, transaction runs out of gas
Attempts:
2 left
💡 Hint
Think about the order: check balance, update balance, then send funds.
❓ Predict Output
intermediate
2: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";
}
ASafe because balance is checked first
BVulnerable to reentrancy attack, balance not updated before sending funds
CTransaction always reverts due to order
DNo difference from original function
Attempts:
2 left
💡 Hint
Consider what happens if the receiver calls back into withdraw before balance changes.
🔧 Debug
advanced
2: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;
    }
}
ALine with call to msg.sender.call{value: amount}("")
BLine with require(balances[msg.sender] >= amount, "Insufficient balance")
CLine with balances[msg.sender] -= amount
DLine with balances[msg.sender] += msg.value
Attempts:
2 left
💡 Hint
Look for interaction before effect.
🧠 Conceptual
advanced
1: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?
ATo prevent reentrancy attacks by updating state before external calls
BTo reduce gas costs by minimizing external calls
CTo allow multiple external calls before state changes
DTo make contracts compatible with all Ethereum clients
Attempts:
2 left
💡 Hint
Think about what kind of attack this pattern helps avoid.
🚀 Application
expert
3: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;
    }
}
AExactly twice, due to call stack limits
BOnly once, because require prevents multiple calls
CZero times, function reverts immediately
DMultiple times until contract runs out of gas or balance
Attempts:
2 left
💡 Hint
Consider that balance is updated after sending funds.

Practice

(1/5)
1.

What is the main purpose of the Checks-Effects-Interactions pattern in smart contracts?

easy
A. To reduce the gas cost of transactions
B. To prevent reentrancy attacks by ordering operations safely
C. To increase the speed of contract execution
D. To allow contracts to call external APIs

Solution

  1. Step 1: Understand the pattern's purpose

    The Checks-Effects-Interactions pattern is designed to prevent security issues by ordering operations carefully.
  2. Step 2: Identify the main security benefit

    By checking conditions first, updating state second, and interacting last, it prevents reentrancy attacks.
  3. Final Answer:

    To prevent reentrancy attacks by ordering operations safely -> Option B
  4. Quick Check:

    Pattern purpose = Prevent reentrancy [OK]
Hint: Remember: check first, update second, interact last [OK]
Common Mistakes:
  • Thinking it speeds up contract execution
  • Believing it reduces gas costs
  • Assuming it enables external API calls
2.

Which of the following Solidity code snippets correctly follows the Checks-Effects-Interactions pattern?

function withdraw(uint amount) public {
  require(balances[msg.sender] >= amount);
  (bool success, ) = msg.sender.call{value: amount}('');
  require(success);
  balances[msg.sender] -= amount;
}
easy
A. Yes, it checks, then interacts, then effects
B. Yes, it updates state before checks
C. No, it interacts before updating state
D. No, it updates state before interaction

Solution

  1. Step 1: Analyze the order of operations

    The code first checks the balance, then calls the external address, then updates the balance.
  2. Step 2: Compare with pattern order

    The pattern requires checks, then effects (state update), then interactions. Here, interaction happens before effects.
  3. Final Answer:

    No, it interacts before updating state -> Option C
  4. Quick Check:

    Interaction before effect = Incorrect order [OK]
Hint: State update must come before external calls [OK]
Common Mistakes:
  • Ignoring the order of state update and interaction
  • Thinking checks alone are enough
  • Confusing effects with interactions
3.

What will be the output of the following Solidity function if balances[msg.sender] is 100 and amount is 50?

function withdraw(uint amount) public {
  require(balances[msg.sender] >= amount);
  balances[msg.sender] -= amount;
  (bool success, ) = msg.sender.call{value: amount}('');
  require(success);
}

Assume the call succeeds.

medium
A. The balance becomes 50 and 50 ether is sent
B. The balance remains 100 and 50 ether is sent
C. The balance becomes 50 but no ether is sent
D. Transaction reverts due to incorrect order

Solution

  1. Step 1: Check balance and update state

    The require passes since 100 >= 50, then balance is reduced to 50.
  2. Step 2: Send ether and confirm success

    The call sends 50 ether and returns success, so require(success) passes.
  3. Final Answer:

    The balance becomes 50 and 50 ether is sent -> Option A
  4. Quick Check:

    Balance updated then ether sent = Correct [OK]
Hint: State updates before sending ether means balance changes [OK]
Common Mistakes:
  • Thinking balance stays the same after withdrawal
  • Assuming call fails without reason
  • Confusing order causing revert
4.

Identify the bug in this Solidity function violating the Checks-Effects-Interactions pattern:

function withdraw(uint amount) public {
  (bool success, ) = msg.sender.call{value: amount}('');
  require(success);
  require(balances[msg.sender] >= amount);
  balances[msg.sender] -= amount;
}
medium
A. It correctly follows the pattern
B. It updates balance before checking conditions
C. It does not check for call success
D. It calls external address before checking balance

Solution

  1. Step 1: Review order of operations

    The function calls the external address first, then checks balance, then updates state.
  2. Step 2: Compare with pattern rules

    Pattern requires checks first, then effects, then interactions. Here, interaction is first, violating the pattern.
  3. Final Answer:

    It calls external address before checking balance -> Option D
  4. Quick Check:

    Interaction before checks = Bug [OK]
Hint: Always check before calling external contracts [OK]
Common Mistakes:
  • Ignoring the order of require and call
  • Assuming call success check is missing
  • Thinking balance update order is wrong
5.

You want to write a Solidity function that sends a reward to a user only if they have enough points. Which code snippet correctly applies the Checks-Effects-Interactions pattern?

function rewardUser(address user, uint points) public {
  // Option A
  require(userPoints[user] >= points);
  userPoints[user] -= points;
  (bool sent, ) = user.call{value: points * 1 ether}('');
  require(sent);

  // Option B
  (bool sent, ) = user.call{value: points * 1 ether}('');
  require(sent);
  require(userPoints[user] >= points);
  userPoints[user] -= points;

  // Option C
  userPoints[user] -= points;
  require(userPoints[user] >= 0);
  (bool sent, ) = user.call{value: points * 1 ether}('');
  require(sent);

  // Option D
  require(userPoints[user] >= points);
  (bool sent, ) = user.call{value: points * 1 ether}('');
  require(sent);
  userPoints[user] -= points;
}
hard
A. Option A
B. Option B
C. Option C
D. Option D

Solution

  1. Step 1: Analyze the order of operations

    The correct snippet first requires userPoints[user] >= points (checks), then subtracts points (effects), then sends ether via call (interactions).
  2. Step 2: Identify violations in others

    The second snippet interacts before checks; the third updates state before checks; the fourth interacts before effects.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Checks -> Effects -> Interactions = Correct snippet [OK]
Hint: Check first, update second, call last for safety [OK]
Common Mistakes:
  • Calling external before checking conditions
  • Updating state before checks
  • Mixing order of effects and interactions
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard