Bird
Raised Fist0
Blockchain / Solidityprogramming~10 mins

Withdrawal patterns in Blockchain / Solidity - Interactive Code Practice

Choose your learning style10 modes available
Practice - 5 Tasks
Answer the questions below
1fill in blank
easy

Complete the code to declare a withdrawal function that sends funds to a user.

Blockchain / Solidity
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount, "Insufficient funds");
    payable(msg.sender).[1](amount);
}
Drag options to blanks, or click blank then click option'
AsendFunds
Bapprove
Cdeposit
Dtransfer
Attempts:
3 left
💡 Hint
Common Mistakes
Using 'deposit' instead of 'transfer' to send funds.
Using 'approve' which is for token allowances, not sending Ether.
2fill in blank
medium

Complete the code to update the user's balance after withdrawal.

Blockchain / Solidity
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount, "Insufficient funds");
    balances[msg.sender] [1] amount;
    payable(msg.sender).transfer(amount);
}
Drag options to blanks, or click blank then click option'
A-=
B*=
C+=
D/=
Attempts:
3 left
💡 Hint
Common Mistakes
Using '+=' which would increase the balance incorrectly.
Using '*=' or '/=' which are not appropriate here.
3fill in blank
hard

Fix the error in the withdrawal pattern to prevent reentrancy attacks.

Blockchain / Solidity
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount, "Insufficient funds");
    balances[msg.sender] [1] amount;
    payable(msg.sender).transfer(amount);
}
Drag options to blanks, or click blank then click option'
A-=
B+=
C=
D*=
Attempts:
3 left
💡 Hint
Common Mistakes
Updating balance after transfer, which can cause reentrancy.
Using '=' which overwrites balance incorrectly.
4fill in blank
hard

Fill both blanks to implement the Checks-Effects-Interactions pattern correctly.

Blockchain / Solidity
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount, "Insufficient funds");
    balances[msg.sender] [1] amount;
    payable(msg.sender).[2](amount);
}
Drag options to blanks, or click blank then click option'
A-=
Bsend
Ctransfer
D+=
Attempts:
3 left
💡 Hint
Common Mistakes
Sending Ether before updating balance.
Using 'send' which returns a boolean and requires extra checks.
5fill in blank
hard

Fill all three blanks to create a safe withdrawal function using the withdrawal pattern.

Blockchain / Solidity
function withdraw(uint amount) public {
    uint balance = balances[msg.sender];
    require(balance [1] amount, "Insufficient funds");
    balances[msg.sender] [2] amount;
    (bool success, ) = payable(msg.sender).[3]{value: amount}("");
    require(success, "Transfer failed.");
}
Drag options to blanks, or click blank then click option'
A>=
B-=
Ccall
D+=
Attempts:
3 left
💡 Hint
Common Mistakes
Using '+=' to update balance which increases it.
Using 'transfer' instead of 'call' which is safer in some cases.
Not checking the success of the call.

Practice

(1/5)
1. What is the main purpose of using a withdrawal pattern in blockchain smart contracts?
easy
A. To let users safely withdraw their funds by calling a function
B. To automatically send funds to users without their request
C. To increase the contract's balance automatically
D. To prevent users from withdrawing funds

Solution

  1. Step 1: Understand withdrawal pattern purpose

    The withdrawal pattern lets users request their funds instead of sending automatically.
  2. Step 2: Identify safety benefits

    This prevents security issues like reentrancy by updating balances before sending.
  3. Final Answer:

    To let users safely withdraw their funds by calling a function -> Option A
  4. Quick Check:

    Withdrawal pattern = user-initiated safe withdrawal [OK]
Hint: Withdrawal pattern means user calls to get funds safely [OK]
Common Mistakes:
  • Thinking funds are sent automatically
  • Confusing withdrawal with deposit
  • Ignoring security benefits
2. Which of the following Solidity code snippets correctly implements the withdrawal pattern?
easy
A. function withdraw() public { payable(msg.sender).transfer(balances[msg.sender]); balances[msg.sender] = 0; }
B. function withdraw() public { payable(msg.sender).transfer(1 ether); }
C. function withdraw() public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; payable(msg.sender).transfer(amount); }
D. function withdraw() public { balances[msg.sender] += 1 ether; }

Solution

  1. Step 1: Check balance update before transfer

    function withdraw() public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; payable(msg.sender).transfer(amount); } sets balance to zero before sending funds, preventing reentrancy.
  2. Step 2: Verify other options

    function withdraw() public { payable(msg.sender).transfer(balances[msg.sender]); balances[msg.sender] = 0; } sends funds before zeroing balance (unsafe). Options C and D do not handle balances properly.
  3. Final Answer:

    function withdraw() public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; payable(msg.sender).transfer(amount); } -> Option C
  4. Quick Check:

    Update balance before transfer = function withdraw() public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; payable(msg.sender).transfer(amount); } [OK]
Hint: Set balance to zero before sending funds [OK]
Common Mistakes:
  • Sending funds before updating balance
  • Not updating balance at all
  • Sending fixed amounts ignoring user balance
3. What will be the output if a user calls withdraw() twice in a row on this contract snippet?
mapping(address => uint) balances;

function withdraw() public {
  uint amount = balances[msg.sender];
  balances[msg.sender] = 0;
  payable(msg.sender).transfer(amount);
}
medium
A. The user receives funds both times
B. The user receives double the funds on second call
C. The contract throws an error on second call
D. The user receives funds only the first time, second call sends zero

Solution

  1. Step 1: Analyze first withdraw call

    First call reads balance, sends funds, then sets balance to zero.
  2. Step 2: Analyze second withdraw call

    Second call reads balance which is now zero, so sends zero funds.
  3. Final Answer:

    The user receives funds only the first time, second call sends zero -> Option D
  4. Quick Check:

    Balance zero after first withdraw = second call sends zero [OK]
Hint: Balance zeroed after first withdraw means second sends zero [OK]
Common Mistakes:
  • Assuming funds sent twice
  • Expecting error on second call
  • Thinking balance resets automatically
4. Identify the bug in this withdrawal function:
function withdraw() public {
  payable(msg.sender).transfer(balances[msg.sender]);
  balances[msg.sender] = 0;
}
medium
A. Balance is never updated
B. Balance is updated after transfer, risking reentrancy attack
C. Function does not send funds
D. Function uses wrong address type

Solution

  1. Step 1: Check order of operations

    The function sends funds before setting balance to zero.
  2. Step 2: Understand security risk

    This allows reentrancy attacks where attacker calls withdraw repeatedly before balance is zeroed.
  3. Final Answer:

    Balance is updated after transfer, risking reentrancy attack -> Option B
  4. Quick Check:

    Update balance before transfer to prevent reentrancy [OK]
Hint: Always update balance before sending funds [OK]
Common Mistakes:
  • Updating balance after transfer
  • Ignoring reentrancy risks
  • Not using payable correctly
5. You want to implement a withdrawal pattern that also logs each withdrawal event with amount and user address. Which of the following Solidity code snippets correctly does this safely?
hard
A. event Withdraw(address indexed user, uint amount); function withdraw() public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; payable(msg.sender).transfer(amount); emit Withdraw(msg.sender, amount); }
B. event Withdraw(address indexed user, uint amount); function withdraw() public { payable(msg.sender).transfer(balances[msg.sender]); emit Withdraw(msg.sender, balances[msg.sender]); balances[msg.sender] = 0; }
C. event Withdraw(address indexed user, uint amount); function withdraw() public { emit Withdraw(msg.sender, balances[msg.sender]); balances[msg.sender] = 0; payable(msg.sender).transfer(balances[msg.sender]); }
D. event Withdraw(address indexed user, uint amount); function withdraw() public { balances[msg.sender] = 0; emit Withdraw(msg.sender, balances[msg.sender]); payable(msg.sender).transfer(balances[msg.sender]); }

Solution

  1. Step 1: Check balance update and transfer order

    event Withdraw(address indexed user, uint amount); function withdraw() public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; payable(msg.sender).transfer(amount); emit Withdraw(msg.sender, amount); } updates balance before transfer, preventing reentrancy.
  2. Step 2: Verify event emits correct amount

    event Withdraw(address indexed user, uint amount); function withdraw() public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; payable(msg.sender).transfer(amount); emit Withdraw(msg.sender, amount); } emits event after transfer with correct amount saved before zeroing balance.
  3. Step 3: Check other options

    The other snippets emit event with wrong amount or update balance after transfer, causing errors or security risks.
  4. Final Answer:

    event Withdraw(address indexed user, uint amount); function withdraw() public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; payable(msg.sender).transfer(amount); emit Withdraw(msg.sender, amount); } -> Option A
  5. Quick Check:

    Update balance, transfer, then emit event with saved amount [OK]
Hint: Save amount first, update balance, transfer, then emit event [OK]
Common Mistakes:
  • Emitting event before saving amount
  • Updating balance after transfer
  • Emitting event with zero amount
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