Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

ownable.gno

4.63 Kb · 164 lines
  1package rbac
  2
  3import (
  4	"chain"
  5	"errors"
  6)
  7
  8const (
  9	OwnershipTransferEvent        = "OwnershipTransfer"
 10	OwnershipTransferStartedEvent = "OwnershipTransferStarted"
 11)
 12
 13// Ownable2Step implements a two-step ownership transfer mechanism.
 14// It requires the new owner to explicitly accept ownership before the transfer is completed,
 15// preventing accidental transfers to incorrect addresses.
 16//
 17// Note: This package does not verify callers. Consuming realms must extract the actual
 18// caller from the live realm context and pass it to these methods.
 19type Ownable2Step struct {
 20	owner        address
 21	pendingOwner address
 22}
 23
 24// newOwnable2StepWithAddress creates a new Ownable2Step instance with addr as owner.
 25func newOwnable2StepWithAddress(addr address) *Ownable2Step {
 26	return &Ownable2Step{
 27		owner:        addr,
 28		pendingOwner: "",
 29	}
 30}
 31
 32// TransferOwnershipBy initiates ownership transfer by setting newOwner as pending owner.
 33// The newOwner must call AcceptOwnershipBy to complete the transfer.
 34//
 35// Parameters:
 36//   - newOwner: Non-zero, syntactically valid address to record as the pending owner.
 37//   - caller: Address authorized to initiate the transfer; it must equal the current owner.
 38//
 39// Errors:
 40//   - ErrUnauthorized: caller is not the current owner
 41//   - ErrInvalidAddress: newOwner is empty or has an invalid format
 42//
 43// Returns:
 44//   - error: nil when the pending owner is set; otherwise ErrUnauthorized or ErrInvalidAddress.
 45func (o *Ownable2Step) TransferOwnershipBy(newOwner, caller address) error {
 46	if !o.IsOwner(caller) {
 47		return errors.New(ErrUnauthorized)
 48	}
 49
 50	if newOwner == zeroAddress || !newOwner.IsValid() {
 51		return errors.New(ErrInvalidAddress)
 52	}
 53
 54	o.pendingOwner = newOwner
 55
 56	chain.Emit(
 57		OwnershipTransferStartedEvent,
 58		"from", o.owner.String(),
 59		"to", newOwner.String(),
 60	)
 61
 62	return nil
 63}
 64
 65// AcceptOwnershipBy completes the ownership transfer.
 66// Must be called by the pending owner.
 67//
 68// Parameters:
 69//   - caller: Address attempting to accept ownership; it must equal the recorded pending owner.
 70//
 71// Errors:
 72//   - ErrNoPendingOwner: no ownership transfer is pending
 73//   - ErrPendingUnauthorized: caller is not the pending owner
 74//
 75// Returns:
 76//   - error: nil when ownership is transferred to caller; otherwise ErrNoPendingOwner or ErrPendingUnauthorized.
 77func (o *Ownable2Step) AcceptOwnershipBy(caller address) error {
 78	if o.pendingOwner == zeroAddress {
 79		return errors.New(ErrNoPendingOwner)
 80	}
 81
 82	if !o.IsPendingOwner(caller) {
 83		return errors.New(ErrPendingUnauthorized)
 84	}
 85
 86	prevOwner := o.owner
 87	o.owner = o.pendingOwner
 88	o.pendingOwner = ""
 89
 90	chain.Emit(
 91		OwnershipTransferEvent,
 92		"from", prevOwner.String(),
 93		"to", o.owner.String(),
 94	)
 95
 96	return nil
 97}
 98
 99// DropOwnershipBy removes the owner, disabling all owner-only actions.
100// This is irreversible - when ownership is dropped, no future owner-only operations can be performed.
101//
102// Parameters:
103//   - caller: Address requesting the drop; it must equal the current owner.
104//
105// Errors:
106//   - ErrUnauthorized: caller is not the current owner
107//
108// Returns:
109//   - error: nil when owner and pending owner are cleared; otherwise ErrUnauthorized.
110func (o *Ownable2Step) DropOwnershipBy(caller address) error {
111	if !o.IsOwner(caller) {
112		return errors.New(ErrUnauthorized)
113	}
114
115	prevOwner := o.owner
116	o.owner = ""
117	o.pendingOwner = ""
118
119	chain.Emit(
120		OwnershipTransferEvent,
121		"from", prevOwner.String(),
122		"to", "",
123	)
124
125	return nil
126}
127
128// Owner returns the current owner address. Returns empty address if ownership has been dropped.
129//
130// Returns:
131//   - address: Current owner address, or the empty address after ownership is dropped.
132func (o *Ownable2Step) Owner() address {
133	return o.owner
134}
135
136// PendingOwner returns the pending owner address during ownership transfer. Returns empty address if no transfer is pending.
137//
138// Returns:
139//   - address: Pending owner address, or the empty address when no transfer is pending.
140func (o *Ownable2Step) PendingOwner() address {
141	return o.pendingOwner
142}
143
144// IsOwner returns true if the provided caller address is the current owner.
145//
146// Parameters:
147//   - caller: Address to compare with the stored current owner address.
148//
149// Returns:
150//   - bool: true when caller exactly equals the current owner address; false otherwise.
151func (o *Ownable2Step) IsOwner(caller address) bool {
152	return o.owner == caller
153}
154
155// IsPendingOwner returns true if the provided caller address is the pending owner.
156//
157// Parameters:
158//   - caller: Address to compare with the stored pending owner address.
159//
160// Returns:
161//   - bool: true when caller exactly equals the pending owner address; false otherwise.
162func (o *Ownable2Step) IsPendingOwner(caller address) bool {
163	return o.pendingOwner == caller
164}