Search Apps Documentation Source Content File Folder Download Copy Actions Download 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}