Beginner
Understanding the ABI — Kudos board build (step 4/6)
Demystify the ABI.
Developer Beginner
7/7 — Understanding the ABI — Kudos board build (step 4/6)
GoalHarden the app: validate inputs and rate-limit spammers.
What to write
- Errors
declare custom errors for empty, too long, too soon.error EmptyMessage(); error TooLong(); error TooSoon(uint256 readyAt);Custom errors save gas vs revert strings and surface clear causes.
- Limits
set max length and cooldown constants plus lastSent tracking.uint256 private constant MAX_LEN = 140; uint256 private constant COOLDOWN = 60; mapping(address => uint256) private _lastSent;Constants make limits clear; _lastSent tracks rate limiting per sender.
- Guarded send
validate message length and cooldown before writing.function sendKudos(address to, string calldata message) external { 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; emit KudosSent(msg.sender, to, message); }Checks happen before state changes; cooldown uses block timestamps.
Why Guards block empty spam and throttle abuse; custom errors keep gas down.
Try it Deploy; test empty/too-long messages and send twice quickly to see cooldown reverts.
// 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;
uint256 public totalKudos;
event KudosSent(address indexed from, address indexed to, string message);
function sendKudos(address to, string calldata message) external {
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;
emit KudosSent(msg.sender, to, message);
}
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.