Beginner
Reading Contracts on Block Explorers — Kudos board build (step 5/6)
Navigate real contracts.
Developer Beginner
7/7 — Reading Contracts on Block Explorers — Kudos board build (step 5/6)
GoalAdd optional tips: accept ETH, forward it, and track totals.
Bitcoin seems to be a very promising idea. I like the idea of basing security on the assumption that the CPU power of honest participants outweighs that of the attacker.
What to write
- Tip tracking
new mapping for received tips.mapping(address => uint256) public tipsReceived;Public getter lets recipients see how much they’ve earned.
- Payable send
mark sendKudos payable and forward value.function sendKudos(address to, string calldata message) external payable { // ... validations ... _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); }Checks-effects-interactions: update state first, then transfer ETH with call and guard success.
- Event update
include the tip amount in the event.event KudosSent(address indexed from, address indexed to, string message, uint256 tip);Logging the tip makes payouts auditable in explorers.
Why Shows payable patterns, safe forwarding, and transparent accounting.
Try it Send kudos with a small tip; confirm tipsReceived and that the recipient receives ETH.
// 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.