Bird
Raised Fist0
Blockchain / Solidityprogramming~20 mins

Common vulnerability patterns in Blockchain / Solidity - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Blockchain Security Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
Reentrancy Attack Output
What is the output of this simplified Solidity-like pseudocode when a reentrancy attack occurs?
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);
        (bool success,) = msg.sender.call{value: amount}("");
        require(success);
        balances[msg.sender] -= amount;
    }
}

// Attacker calls withdraw repeatedly before balances[msg.sender] is updated.
AThe contract locks funds permanently due to a deadlock in withdraw.
BThe attacker drains all funds by repeatedly calling withdraw before balance updates.
CThe contract rejects the withdrawal due to insufficient balance immediately.
DThe contract throws a compile-time error due to missing return statement.
Attempts:
2 left
💡 Hint
Think about what happens if the external call happens before the balance is updated.
❓ Predict Output
intermediate
1:30remaining
Integer Overflow Result
What is the value of variable `total` after running this Solidity-like pseudocode?
Blockchain / Solidity
uint8 a = 250;
uint8 b = 10;
uint8 total = a + b; // uint8 max is 255
A4
B260
COverflowError at runtime
D250
Attempts:
2 left
💡 Hint
Remember uint8 can only hold values from 0 to 255 and wraps around on overflow.
🔧 Debug
advanced
2:00remaining
Fix the Timestamp Dependency Bug
This smart contract uses block.timestamp to decide a winner. What is the main vulnerability here?
Blockchain / Solidity
contract Lottery {
    address public winner;

    function pickWinner() public {
        require(block.timestamp % 2 == 0, "Not even timestamp");
        winner = msg.sender;
    }
}
AFunction pickWinner is missing a return statement causing compile error.
BThe contract will always revert because block.timestamp is never even.
CMiner can manipulate block.timestamp to influence winner selection.
DThere is no vulnerability; the code is safe.
Attempts:
2 left
💡 Hint
Think about who controls the block timestamp and how it affects randomness.
📝 Syntax
advanced
1:30remaining
Identify the Syntax Error in Access Control
Which option contains the correct Solidity code to restrict a function to the contract owner?
A
modifier onlyOwner() {
    require(msg.sender == owner)
    _;
}
B
modifier onlyOwner() {
    if(msg.sender != owner) {
        revert();
    }
}
C
modifier onlyOwner() {
    require(msg.sender == owner);
    _;
}
D
modifier onlyOwner() {
    require(msg.sender == owner, "Not owner");
    _;
}
Attempts:
2 left
💡 Hint
Look for correct syntax including semicolons and the placeholder _; in modifiers.
🚀 Application
expert
2:30remaining
Detecting Front-Running Vulnerability
Which of the following code snippets is vulnerable to front-running attacks in a blockchain environment?
A
function bid() public payable {
    require(msg.value > highestBid);
    highestBidder = msg.sender;
    highestBid = msg.value;
}
B
function bid() public payable {
    require(msg.value >= highestBid);
    highestBid = msg.value;
    highestBidder = msg.sender;
}
C
function bid() public payable {
    require(msg.value > highestBid);
    emit NewBid(msg.sender, msg.value);
    highestBid = msg.value;
    highestBidder = msg.sender;
}
D
function bid() public payable {
    require(msg.value > highestBid);
    highestBid = msg.value;
    highestBidder = msg.sender;
}
Attempts:
2 left
💡 Hint
Consider the order of state changes and how miners or attackers can exploit it.

Practice

(1/5)
1. Which of the following is a common vulnerability in blockchain smart contracts that allows attackers to repeatedly call a function before the first call finishes?
easy
A. Phishing attack
B. Integer overflow
C. Timestamp dependency
D. Reentrancy attack

Solution

  1. Step 1: Understand reentrancy attack

    Reentrancy happens when a contract calls another contract and the called contract calls back before the first call finishes.
  2. Step 2: Identify the vulnerability type

    This allows attackers to exploit the contract by repeatedly calling a function, draining funds.
  3. Final Answer:

    Reentrancy attack -> Option D
  4. Quick Check:

    Repeated calls before completion = Reentrancy attack [OK]
Hint: Repeated calls before finish? It's reentrancy [OK]
Common Mistakes:
  • Confusing integer overflow with repeated calls
  • Thinking timestamp dependency allows repeated calls
  • Mixing phishing attack with smart contract vulnerabilities
2. Which of the following Solidity code snippets correctly prevents integer overflow using Solidity 0.8+ built-in checks?
easy
A. uint256 x = a + b; // no extra check needed
B. uint256 x = SafeMath.add(a, b);
C. uint256 x = a + b; require(x >= a);
D. uint256 x = a - b; // prevents overflow

Solution

  1. Step 1: Recall Solidity 0.8+ overflow behavior

    From Solidity 0.8, arithmetic operations revert on overflow automatically.
  2. Step 2: Identify correct prevention method

    So, just using uint256 x = a + b; is safe without extra checks or libraries.
  3. Final Answer:

    uint256 x = a + b; // no extra check needed -> Option A
  4. Quick Check:

    Solidity 0.8+ auto checks overflow = uint256 x = a + b; // no extra check needed [OK]
Hint: Solidity 0.8+ auto checks overflow, no SafeMath needed [OK]
Common Mistakes:
  • Using SafeMath in Solidity 0.8+ unnecessarily
  • Adding manual require checks that are redundant
  • Confusing subtraction with addition overflow
3. Consider this Solidity function snippet:
function withdraw(uint amount) public {
  require(balances[msg.sender] >= amount);
  (bool success, ) = msg.sender.call{value: amount}('');
  require(success);
  balances[msg.sender] -= amount;
}
What is the main vulnerability in this code?
medium
A. Integer overflow in balances update
B. Reentrancy attack due to external call before state update
C. Timestamp dependency in withdrawal timing
D. Unchecked call return value

Solution

  1. Step 1: Analyze call order in function

    The external call to msg.sender.call happens before updating balances[msg.sender].
  2. Step 2: Identify vulnerability type

    This allows reentrancy: attacker can call withdraw again before balance is reduced.
  3. Final Answer:

    Reentrancy attack due to external call before state update -> Option B
  4. Quick Check:

    External call before balance update = Reentrancy risk [OK]
Hint: External call before state update? Watch for reentrancy [OK]
Common Mistakes:
  • Thinking integer overflow is the issue here
  • Ignoring call return value is not the main problem
  • Confusing timestamp dependency with this pattern
4. This Solidity code snippet is intended to prevent reentrancy. What is the bug?
mapping(address => uint) public balances;

function withdraw(uint amount) public {
  require(balances[msg.sender] >= amount);
  balances[msg.sender] -= amount;
  (bool success, ) = msg.sender.call{value: amount}('');
  require(success);
  balances[msg.sender] = 0;
}
medium
A. Balance is set to zero after sending funds, causing loss of remaining balance for partial withdrawals
B. No require check on call success
C. Balances mapping is not initialized
D. Function lacks payable modifier

Solution

  1. Step 1: Check balance update order

    Balance is reduced before sending funds (good for reentrancy prevention), but then reset to zero after sending.
  2. Step 2: Identify bug impact

    For partial withdrawals (e.g., balance=20, amount=10), after -=10 and send 10, setting to 0 discards the remaining 10 without sending it, stealing user funds.
  3. Final Answer:

    Balance is set to zero after sending funds, causing loss of remaining balance for partial withdrawals -> Option A
  4. Quick Check:

    Post-call balance=0 after partial -= = remaining balance theft [OK]
Hint: Extra balance=0 after partial -= and send? Steals remainder [OK]
Common Mistakes:
  • Ignoring that balance reset happens after external call
  • Thinking missing payable modifier causes this bug
  • Assuming call success check is missing
5. You want to write a Solidity function that safely transfers tokens and prevents both reentrancy and integer overflow. Which approach is best?
hard
A. Call external contracts first, then update balances with SafeMath
B. Use timestamp checks to limit withdrawals and SafeMath for math
C. Update state variables before external calls and use Solidity 0.8+ arithmetic
D. Avoid updating balances and rely on external contract trust

Solution

  1. Step 1: Prevent reentrancy by state update order

    Update all internal state variables before making any external calls to avoid reentrancy.
  2. Step 2: Prevent integer overflow using Solidity 0.8+

    Use Solidity 0.8+ built-in overflow checks instead of external libraries.
  3. Final Answer:

    Update state variables before external calls and use Solidity 0.8+ arithmetic -> Option C
  4. Quick Check:

    State update first + Solidity 0.8+ overflow checks = Safe transfer [OK]
Hint: Update state before calls; Solidity 0.8+ handles overflow [OK]
Common Mistakes:
  • Calling external contracts before state update
  • Relying on timestamp checks for safety
  • Ignoring overflow checks in older Solidity versions
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