Who is calling: abi.caller and ownership
Without knowing the caller, every function is public to everyone. This is how access control works.
abi.caller() returns the address that invoked this call, as bytes. It is how a contract tells its owner from a stranger.
from stdlib import abi, storage
K_OWNER = b"demo:owner"
def init(owner: bytes) -> None:
storage.set(K_OWNER, bytes(owner))
def _only_owner() -> None:
abi.require(abi.caller() == storage.get(K_OWNER, b""), b"not_owner")
The context also gives you:
| call | what it is |
|---|---|
abi.caller() | who called *this* contract (may be another contract) |
abi.tx_origin() | the account that signed the transaction |
abi.self_address() | this contract's own address |
abi.block_height() | the height this call is executing at |
abi.block_timestamp() | the block's timestamp |
abi.chain_id() | 1 on Animica mainnet |
Use caller(), not tx_origin(), for authorisation. If contract B calls your contract, caller() is B while tx_origin() is still the human who started the chain of calls. Authorising on tx_origin means any contract a user touches can act as that user — the classic phishing hole. tx_origin is for telemetry, not permissions.
Your turn
Build an owned counter. init(owner) records the owner. bump() may only be called by the owner and increments; anyone else gets b"not_owner". owner() returns the stored owner.
Hints
One way to do it
from stdlib import abi, storage
K_OWNER = b"demo:owner"
K_N = b"demo:n"
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 init(owner_addr: bytes) -> None:
abi.require(len(owner_addr) > 0, b"bad_owner")
storage.set(K_OWNER, bytes(owner_addr))
def owner() -> bytes:
return storage.get(K_OWNER, b"")
def bump() -> int:
abi.require(abi.caller() == storage.get(K_OWNER, b""), b"not_owner")
_uset(K_N, _uget(K_N) + 1)
return _uget(K_N)
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.