Beginner

Intro to Hardhat / Foundry — Kudos board build (step 6/6)

Learn the dev workflow.

Developer Beginner
7/7 — Intro to Hardhat / Foundry — Kudos board build (step 6/6)

GoalFinalize the contract for tooling and tests—no new logic, just polish and readiness.

What to write

  1. Lock surface
    review functions/events and confirm modifiers/visibility are intentional.
  2. Keep payable logic
    same guarded sendKudos with tipping and events.
  3. Ready for tests
    note what to cover: emits event, cooldown enforced, tip forwarded, counters increment.

Why This is the version you’ll deploy and test with Hardhat/Foundry; consistency matters for scripts and ABIs.

Try it Write a deploy script plus two tests: one for event + counters, one that expects the cooldown revert.

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

contract KudosBoard {
    error EmptyMessage();
    error TooLong();
    error TooSoon(uint256 readyAt);

    uint256 private constant MAX_LEN = 140;
    uint256 private constant COOLDOWN = 60;

    mapping(address => string) private _lastKudos;
    mapping(address => uint256) public kudosCount;
    mapping(address => uint256) private _lastSent;
    mapping(address => uint256) public tipsReceived;
    uint256 public totalKudos;

    event KudosSent(address indexed from, address indexed to, string message, uint256 tip);

    function sendKudos(address to, string calldata message) external payable {
        if (bytes(message).length == 0) revert EmptyMessage();
        if (bytes(message).length > MAX_LEN) revert TooLong();
        uint256 ready = _lastSent[msg.sender] + COOLDOWN;
        if (block.timestamp < ready) revert TooSoon(ready);

        _lastKudos[to] = message;
        kudosCount[to] += 1;
        totalKudos += 1;
        _lastSent[msg.sender] = block.timestamp;
        if (msg.value > 0) {
            tipsReceived[to] += msg.value;
            (bool ok, ) = to.call{value: msg.value}('');
            require(ok, 'tip failed');
        }
        emit KudosSent(msg.sender, to, message, msg.value);
    }

    function lastKudos(address user) external view returns (string memory) {
        return _lastKudos[user];
    }
}

NextWe’ll keep extending this in the following lesson; this version already deploys and runs.

← Previous section
Start quiz →