Events: telling the outside world
Storage is what your contract knows. Events are what it announces. Indexers, wallets and explorers read events, not storage.
events.emit(name, fields) writes a log entry into the transaction receipt. The name is bytes; the fields are a dict.
from stdlib import events
events.emit(b"Transfer", {"from": sender, "to": recipient, "value": amount})
Events do not change state and cannot be read back by a contract — not by yours, not by anyone's. They exist for off-chain consumers: block explorers, wallets showing your balance, an indexer building a leaderboard.
If a call reverts, its events go with it. A receipt only ever contains events from calls that actually succeeded.
Emit after the state change, not before. The event describes something that happened; if you emit first and then hit a require that fails, the event is discarded anyway — but code that reads in the order things occur is easier to audit, and reviewers look for exactly this.
Your turn
Add an event to a transfer-like function. send(to, amount) should deduct from the caller's balance and emit Sent with fields to and amount. Reject overdrafts with b"insufficient".
Hints
have >= amt and revert with b"insufficient" before writing.One way to do it
from stdlib import abi, events, storage
def _k_bal(addr: bytes) -> bytes:
return b"demo:bal:" + addr
def _uget(key: bytes) -> int:
raw = storage.get(key, b"")
return 0 if raw == b"" else int.from_bytes(raw, "big")
def _uset(key: bytes, value: int) -> None:
v = int(value)
if v == 0:
storage.delete(key)
return
storage.set(key, v.to_bytes(max(1, (v.bit_length() + 7) // 8), "big"))
def credit(addr: bytes, amount: int) -> None:
_uset(_k_bal(bytes(addr)), _uget(_k_bal(bytes(addr))) + int(amount))
def balance_of(addr: bytes) -> int:
return _uget(_k_bal(bytes(addr)))
def send(to: bytes, amount: int) -> int:
amt = int(amount)
me = abi.caller()
have = _uget(_k_bal(me))
abi.require(amt > 0, b"must_be_positive")
abi.require(have >= amt, b"insufficient")
_uset(_k_bal(me), have - amt)
_uset(_k_bal(bytes(to)), _uget(_k_bal(bytes(to))) + amt)
events.emit(b"Sent", {"to": bytes(to), "amount": amt})
return _uget(_k_bal(me))
Claim your 10 ANM
Finish this lesson and claim 10 ANM, once per address. Paid from the Animica treasury in batches — allow a few minutes.
Stuck? Ask
Answered by Animica's own free inference network. It is donated GPU capacity, so give it 20-30 seconds.