This pattern helps keep blockchain programs safe by avoiding problems when multiple actions happen together. It stops bad things like losing money or breaking the program.
Checks-Effects-Interactions pattern in Blockchain / Solidity
function example() public {
// 1. Checks: Verify conditions
require(condition, "Check failed");
// 2. Effects: Update contract state
stateVariable = newValue;
// 3. Interactions: Call external contracts or send money
externalContract.call{value: amount}();
}Always do checks first to make sure everything is okay.
Update your own data before talking to others.
function withdraw(uint amount) public {
// Checks
require(balances[msg.sender] >= amount, "Not enough balance");
// Effects
balances[msg.sender] -= amount;
// Interactions
payable(msg.sender).transfer(amount);
}function buyItem(uint itemId) public payable {
// Checks
require(items[itemId].available, "Item not available");
require(msg.value >= items[itemId].price, "Not enough payment");
// Effects
items[itemId].available = false;
ownerBalances[owner] += msg.value;
// Interactions
seller.call{value: msg.value}();
}This smart contract lets users deposit and withdraw money safely. The withdraw function uses the Checks-Effects-Interactions pattern to avoid problems like reentrancy attacks.
pragma solidity ^0.8.0; contract SimpleBank { mapping(address => uint) public balances; // Deposit money to your balance function deposit() public payable { balances[msg.sender] += msg.value; } // Withdraw money safely using Checks-Effects-Interactions function withdraw(uint amount) public { // Checks require(balances[msg.sender] >= amount, "Insufficient balance"); // Effects balances[msg.sender] -= amount; // Interactions payable(msg.sender).transfer(amount); } }
Never call external contracts before updating your own data.
Use require() to stop bad actions early.
This pattern helps prevent common security bugs in blockchain programs.
Checks-Effects-Interactions means: check conditions, update your data, then interact with others.
It keeps your smart contracts safe and reliable.
Always follow this order when writing functions that send money or call other contracts.
Practice
What is the main purpose of the Checks-Effects-Interactions pattern in smart contracts?
Solution
Step 1: Understand the pattern's purpose
The Checks-Effects-Interactions pattern is designed to prevent security issues by ordering operations carefully.Step 2: Identify the main security benefit
By checking conditions first, updating state second, and interacting last, it prevents reentrancy attacks.Final Answer:
To prevent reentrancy attacks by ordering operations safely -> Option BQuick Check:
Pattern purpose = Prevent reentrancy [OK]
- Thinking it speeds up contract execution
- Believing it reduces gas costs
- Assuming it enables external API calls
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;
}Solution
Step 1: Analyze the order of operations
The code first checks the balance, then calls the external address, then updates the balance.Step 2: Compare with pattern order
The pattern requires checks, then effects (state update), then interactions. Here, interaction happens before effects.Final Answer:
No, it interacts before updating state -> Option CQuick Check:
Interaction before effect = Incorrect order [OK]
- Ignoring the order of state update and interaction
- Thinking checks alone are enough
- Confusing effects with interactions
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.
Solution
Step 1: Check balance and update state
The require passes since 100 >= 50, then balance is reduced to 50.Step 2: Send ether and confirm success
The call sends 50 ether and returns success, so require(success) passes.Final Answer:
The balance becomes 50 and 50 ether is sent -> Option AQuick Check:
Balance updated then ether sent = Correct [OK]
- Thinking balance stays the same after withdrawal
- Assuming call fails without reason
- Confusing order causing revert
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;
}Solution
Step 1: Review order of operations
The function calls the external address first, then checks balance, then updates state.Step 2: Compare with pattern rules
Pattern requires checks first, then effects, then interactions. Here, interaction is first, violating the pattern.Final Answer:
It calls external address before checking balance -> Option DQuick Check:
Interaction before checks = Bug [OK]
- Ignoring the order of require and call
- Assuming call success check is missing
- Thinking balance update order is wrong
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;
}Solution
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).Step 2: Identify violations in others
The second snippet interacts before checks; the third updates state before checks; the fourth interacts before effects.Final Answer:
Option A -> Option AQuick Check:
Checks -> Effects -> Interactions = Correct snippet [OK]
- Calling external before checking conditions
- Updating state before checks
- Mixing order of effects and interactions
Ready to prove it?
Pass the test and this pattern moves unknown
