BC7: Writing smart contracts in Solidity
Who may do what: modifiers, errors and events
🎯You'll be able to
Restrict functions to the right callers, refuse bad input with clear errors, and record actions with events.
🏠The everyday picture
A bank counter with a sign saying "Account holders only", a clerk who explains exactly why a form is refused, and a ledger slip for every transaction.
📘What it really is
- Access control: check
msg.senderagainst the admin or a role at the start of a function. - Modifiers: reusable checks such as
onlyAdminorwhenNotPaused, placed on functions. -
msg.sender, not tx.origin:
tx.originis the person who started the whole transaction, even if they were tricked into calling a malicious contract that then calls yours. Usemsg.senderfor authorisation. -
Custom errors:
error TooMuch(uint256 requested, uint256 available);withrevert TooMuch(...). Cheaper than text messages, and apps can decode them into plain words. -
Events:
emit Deposited(member, amount);. Indexed fields can be searched. Every state change people care about should emit one.
📝A worked example
Input: only the admin may add members, and the app must explain refusals.
Steps:
modifier onlyAdmin() { if (msg.sender != admin) revert NotAdmin(); _; }.function addMember(address member) external onlyAdmin { ... emit MemberAdded(member); }.- The app catches the error, decodes
NotAdminand shows "Only the group's admin can do that."
Expected output: the right callers, clear refusals and a searchable record.
🌍Where it's used
- Ownable and role-based access patterns in contract libraries such as OpenZeppelin.
- Custom errors in modern contracts.
- Events read by apps and explorers.
📝Case scenario
A contract checked tx.origin == owner. An attacker sent the owner a link to a "free airdrop" contract; when the owner called it, the
attacker's contract called the victim contract, and the check passed because the owner had started the transaction. Switching to
msg.sender stopped it.
🖱️Try it
Find the tx.origin check in the starter's addMember and explain, in two sentences, how the kit's Phisher contract uses it.
Success: the admin calls Phisher, and Phisher calls addMember while tx.origin is still the admin.
⚠️Common mistakes
tx.originfor authorisation. Sign: phishing contracts can act as you. Fix:msg.sender.- Missing access checks. Sign: anyone can call admin functions. Fix: modifiers on every sensitive function.
- No events. Sign: apps can't follow changes. Fix: emit for each change.
🛠️For your project
Project 1's test 4 uses the Phisher contract to check that only the admin can add members or pause.
✅Quick check
Why use msg.sender instead of tx.origin for authorisation?
Show the answer
tx.origin stays the original caller even when a malicious contract is in between.
What do custom errors give an app?
Show the answer
A named reason it can decode into plain words.
