ownable.gno
3.03 Kb ยท 124 lines
1package ownable2step
2
3import (
4 "chain"
5 "chain/runtime"
6)
7
8const OwnershipTransferEvent = "OwnershipTransfer"
9
10// Ownable2Step is a two-step ownership transfer package
11// It allows the current owner to set a new owner and the new owner will need to accept the ownership before it is transferred
12// XXX Implement using Ownable instead of replicating it.
13type Ownable2Step struct {
14 owner address
15 pendingOwner address
16}
17
18func New() *Ownable2Step {
19 return &Ownable2Step{
20 owner: runtime.CurrentRealm().Address(),
21 pendingOwner: "",
22 }
23}
24
25func NewWithOrigin() *Ownable2Step {
26 origin := runtime.OriginCaller()
27 previous := runtime.PreviousRealm()
28 if origin != previous.Address() {
29 panic("NewWithOrigin() should be called from init() where std.PreviousRealm() is origin")
30 }
31 return &Ownable2Step{
32 owner: origin,
33 }
34}
35
36func NewWithAddress(addr address) *Ownable2Step {
37 return &Ownable2Step{
38 owner: addr,
39 pendingOwner: "",
40 }
41}
42
43// TransferOwnership initiate the transfer of the ownership to a new address by setting the PendingOwner
44func (o *Ownable2Step) TransferOwnership(newOwner address) error {
45 if !o.OwnedByCurrent() {
46 return ErrUnauthorized
47 }
48 if !newOwner.IsValid() {
49 return ErrInvalidAddress
50 }
51
52 o.pendingOwner = newOwner
53 return nil
54}
55
56// AcceptOwnership accepts the pending ownership transfer
57func (o *Ownable2Step) AcceptOwnership() error {
58 if o.pendingOwner.String() == "" {
59 return ErrNoPendingOwner
60 }
61 if runtime.CurrentRealm().Address() != o.pendingOwner {
62 return ErrPendingUnauthorized
63 }
64
65 o.owner = o.pendingOwner
66 o.pendingOwner = ""
67
68 return nil
69}
70
71// DropOwnership removes the owner, effectively disabling any owner-related actions
72// Top-level usage: disables all only-owner actions/functions,
73// Embedded usage: behaves like a burn functionality, removing the owner from the struct
74func (o *Ownable2Step) DropOwnership() error {
75 if !o.OwnedByCurrent() {
76 return ErrUnauthorized
77 }
78
79 prevOwner := o.owner
80 o.owner = ""
81 o.pendingOwner = ""
82
83 chain.Emit(
84 OwnershipTransferEvent,
85 "from", prevOwner.String(),
86 "to", "",
87 )
88
89 return nil
90}
91
92// Owner returns the owner address from Ownable
93func (o *Ownable2Step) Owner() address {
94 return o.owner
95}
96
97// PendingOwner returns the pending owner address from Ownable2Step
98func (o *Ownable2Step) PendingOwner() address {
99 return o.pendingOwner
100}
101
102// OwnedByCurrent checks if the caller of the function is the Realm's owner
103func (o *Ownable2Step) OwnedByCurrent() bool {
104 return runtime.CurrentRealm().Address() == o.owner
105}
106
107// AssertOwnedByCurrent panics if the caller is not the owner
108func (o *Ownable2Step) AssertOwnedByCurrent() {
109 if runtime.CurrentRealm().Address() != o.owner {
110 panic(ErrUnauthorized)
111 }
112}
113
114// OwnedByPrevious checks if the caller of the function is the Realm's owner
115func (o *Ownable2Step) OwnedByPrevious() bool {
116 return runtime.PreviousRealm().Address() == o.owner
117}
118
119// AssertOwnedByPrevious panics if the caller is not the owner
120func (o *Ownable2Step) AssertOwnedByPrevious() {
121 if runtime.PreviousRealm().Address() != o.owner {
122 panic(ErrUnauthorized)
123 }
124}