iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Exercises

Three short Solidity exercises - safe patterns you should know cold before deploying anything that holds value.

Three short challenges

EXAMPLE
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

// 1. Reentrancy-safe withdraw
// Vulnerable pattern uses external call before state update.
contract Vault {
    mapping(address => uint256) public balances;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }

    // GOOD - checks-effects-interactions
    function withdraw(uint256 amount) external {
        require(balances[msg.sender] >= amount, 'insufficient');
        balances[msg.sender] -= amount;                           // effect first
        (bool ok, ) = msg.sender.call{value: amount}('');         // interaction last
        require(ok, 'transfer failed');
    }
}


// 2. Pull-over-push payments
contract Payouts {
    mapping(address => uint256) public owed;

    function recordPayout(address recipient, uint256 amount) external {
        owed[recipient] += amount;
    }

    // Recipients withdraw themselves; we never push.
    function claim() external {
        uint256 amount = owed[msg.sender];
        require(amount > 0, 'nothing to claim');
        owed[msg.sender] = 0;
        (bool ok, ) = msg.sender.call{value: amount}('');
        require(ok, 'claim failed');
    }
}


// 3. Access control with OpenZeppelin
import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { AccessControl } from '@openzeppelin/contracts/access/AccessControl.sol';

contract Treasury is AccessControl {
    bytes32 public constant TREASURER = keccak256('TREASURER');

    constructor(address admin) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
    }

    function spend(address payable to, uint256 amount) external onlyRole(TREASURER) {
        (bool ok, ) = to.call{value: amount}('');
        require(ok);
    }

    receive() external payable {}
}


// Testing tips
// - Use Foundry: forge test -vvv
// - Property-based tests (forge test --match-test invariant_*) catch what unit tests miss
// - Slither and Mythril for static analysis - add to CI

Why it matters

Audit before you deploy. The three patterns here cover most low-hanging fruit, but real audits are about reading the code in context. Pair tests with Foundry invariants, run Slither in CI, and have at least one fresh pair of eyes review.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Fill in: function bump() ____ { n += 1; }   // callable by anyone, modifies state
Try it Yourself »

Discussion

Loading…