v0 source pure
v0 - Unaudited: This is an initial version that has not yet been formally audited. A fully audited version will be pu...
View source
v0 - Unaudited This is an initial version of this package that has not yet been formally audited. A fully audited version will be published as a subsequent release. Use in production at your own risk.
ownable - Ownership pattern for realms
Provides an Ownable object that gates privileged operations behind a single owner address. Embed it in a realm (or any struct) to restrict actions like configuration changes, withdrawals, or upgrades.
Usage
1package myrealm
2
3import (
4 "chain/runtime"
5
6 "gno.land/p/nt/ownable/v0"
7)
8
9// The owner address is chosen explicitly at construction. A common
10// choice is the deployer, captured in init after confirming it is a
11// real user call.
12var owner *ownable.Ownable
13
14func init() {
15 caller := runtime.PreviousRealm()
16 if !caller.IsUserCall() {
17 panic("must be deployed by a user")
18 }
19 owner = ownable.NewWithAddress(caller.Address())
20}
21
22// SetFee is gated: only the current owner may call it.
23func SetFee(cur realm, newFee int64) {
24 if !cur.IsCurrent() {
25 panic("spoofed realm")
26 }
27 owner.AssertOwnedBy(cur.Previous().Address())
28 fee = newFee
29}
30
31// Hand the realm over. TransferOwnership itself verifies the caller is owner.
32func TransferOwner(cur realm, to address) error {
33 return owner.TransferOwnership(0, cur, to)
34}
There is no auth-mode flag. The single NewWithAddress constructor replaced the
old New / NewWithOrigin / NewWithAddressByPrevious sugar: the realm now picks
the owner address explicitly rather than baking a runtime walk into the struct.
API
1type Ownable struct{ /* unexported */ }
2
3const OwnershipTransferEvent = "OwnershipTransfer"
4
5var (
6 ErrUnauthorized = errors.New("ownable: caller is not owner")
7 ErrInvalidAddress = errors.New("ownable: new owner address is invalid")
8)
9
10// NewWithAddress is the only constructor: the realm picks the owner
11// address explicitly (e.g. cur.Previous().Address() after checking
12// cur.Previous().IsUserCall() in init).
13func NewWithAddress(addr address) *Ownable
14
15// Queries (caller supplies the address to check).
16func (o *Ownable) Owner() address // "" if o is nil or ownership was dropped
17func (o *Ownable) OwnedBy(addr address) bool // true if addr is the current owner
18func (o *Ownable) AssertOwnedBy(addr address) // panics with ErrUnauthorized if addr is not the owner
19
20// Authority mutation (thread the caller's own cur; pass 0 as the first arg).
21func (o *Ownable) TransferOwnership(_ int, rlm realm, newOwner address) error
22func (o *Ownable) DropOwnership(_ int, rlm realm) error // sets owner to "" — irreversible
Notes
- Authority-mutating methods assert
rlm.IsCurrent()and identify the caller asrlm.Previous().Address(), which must equal the current owner. The principal is therefore unforgeable: an attacker cannot supply an arbitrary caller address. Pass0as the placeholder first arg and your owncurasrlm. - Read helpers (
OwnedBy,AssertOwnedBy) take a bare address; the caller extracts it, guarding withcur.IsCurrent()before readingcur.Previous().Address(). TransferOwnershiprejects an invalidnewOwnerwithErrInvalidAddress. Both mutators emitOwnershipTransferEventwithfromandtofields.DropOwnershipis permanent:ownerbecomes"", so every owner-gated action becomes unreachable.
v0 - Unaudited: This is an initial version that has not yet been formally audited. A fully audited version will be published as a subsequent release. Use in production at your own risk.
Package ownable provides an ownership pattern for Gno realms, allowing contracts to restrict access to privileged operations to a designated owner.
1
1
1
func NewWithAddress
NewWithAddress creates an Ownable with the given address as owner. This is the only constructor — the previous New/NewWithOrigin/ NewWithAddressByPrevious sugar baked runtime walks and an auth-mode flag into the struct; the realm using this package now picks the owner address explicitly (e.g. cur.Previous().Address() after verifying cur.Previous().IsUserCall() in init).
1
type Ownable
structOwnable is meant to be used as a top-level object to make your contract ownable OR being embedded in a Gno object to manage per-object ownership. Ownable is safe to export as a top-level object.
Authority-mutating methods (TransferOwnership, DropOwnership) take (_ int, rlm realm). The caller threads its own cur; the method asserts rlm.IsCurrent() and identifies the principal as rlm.Previous().Address() — which must equal the current owner.
Read methods (OwnedBy, AssertOwnedBy) keep the bare-address shape; callers extract the address themselves (e.g. cur.Previous().Address()).
Methods on Ownable
func AssertOwnedBy
method on OwnableAssertOwnedBy panics with ErrUnauthorized if addr is not the owner.
func DropOwnership
method on OwnableDropOwnership removes the owner, disabling any owner-related actions. rlm must be the caller's own captured cur; rlm.Previous().Address() must equal the current owner.
func OwnedBy
method on OwnableOwnedBy reports whether addr is the current owner.
func Owner
method on OwnableOwner returns the owner address.
func TransferOwnership
method on OwnableTransferOwnership transfers ownership of the Ownable to newOwner. rlm must be the caller's own captured cur (asserted via rlm.IsCurrent()). The principal is rlm.Previous().Address() — the realm that crossed into the caller — which must equal the current owner.
IsCurrent + rlm.Previous() makes the principal unforgeable: an attacker calling TransferOwnership on a foreign Ownable cannot supply an arbitrary caller address; rlm comes from a runtime-validated crossing frame.
2
- chain stdlib
- errors stdlib