ownable.gno
2.96 Kb ยท 128 lines
1package ownable
2
3import (
4 "chain"
5 "chain/runtime"
6)
7
8const OwnershipTransferEvent = "OwnershipTransfer"
9
10// Ownable is meant to be used as a top-level object to make your contract ownable OR
11// being embedded in a Gno object to manage per-object ownership.
12// Ownable is safe to export as a top-level object
13type Ownable struct {
14 owner address
15}
16
17func New() *Ownable {
18 return &Ownable{
19 owner: runtime.CurrentRealm().Address(),
20 }
21}
22
23func NewWithOrigin() *Ownable {
24 origin := runtime.OriginCaller()
25 previous := runtime.PreviousRealm()
26 if origin != previous.Address() {
27 panic("NewWithOrigin() should be called from init() where std.PreviousRealm() is origin")
28 }
29 return &Ownable{
30 owner: origin,
31 }
32}
33
34func NewWithAddress(addr address) *Ownable {
35 return &Ownable{
36 owner: addr,
37 }
38}
39
40// TransferOwnership transfers ownership of the Ownable struct to a new address
41func (o *Ownable) TransferOwnership(newOwner address) error {
42 if !o.OwnedByCurrent() {
43 return ErrUnauthorized
44 }
45
46 if !newOwner.IsValid() {
47 return ErrInvalidAddress
48 }
49
50 prevOwner := o.owner
51 o.owner = newOwner
52 chain.Emit(
53 OwnershipTransferEvent,
54 "from", prevOwner.String(),
55 "to", newOwner.String(),
56 )
57
58 return nil
59}
60
61// DropOwnershipByCurrent removes the owner, effectively disabling any owner-related actions
62// Top-level usage: disables all only-owner actions/functions,
63// Embedded usage: behaves like a burn functionality, removing the owner from the struct
64func (o *Ownable) DropOwnershipByCurrent() error {
65 if !o.OwnedByCurrent() {
66 return ErrUnauthorized
67 }
68 o.dropOwnership(o.owner)
69 return nil
70}
71
72// DropOwnershipByPrevious removes the owner, effectively disabling any owner-related actions
73// Top-level usage: disables all only-owner actions/functions,
74// Embedded usage: behaves like a burn functionality, removing the owner from the struct
75func (o *Ownable) DropOwnershipByPrevious() error {
76 if !o.OwnedByPrevious() {
77 return ErrUnauthorized
78 }
79 o.dropOwnership(o.owner)
80 return nil
81}
82
83func (o *Ownable) dropOwnership(prevOwner address) {
84 o.owner = ""
85 chain.Emit(
86 OwnershipTransferEvent,
87 "from", prevOwner.String(),
88 "to", "",
89 )
90}
91
92// Owner returns the owner address from Ownable
93func (o *Ownable) Owner() address {
94 if o == nil {
95 return address("")
96 }
97 return o.owner
98}
99
100// OwnedByCurrent checks if the caller of the function is the Realm's owner
101func (o *Ownable) OwnedByCurrent() bool {
102 if o == nil {
103 return false
104 }
105 return runtime.CurrentRealm().Address() == o.owner
106}
107
108// AssertOwnedByCurrent panics if the caller is not the owner
109func (o *Ownable) AssertOwnedByCurrent() {
110 if !o.OwnedByCurrent() {
111 panic(ErrUnauthorized)
112 }
113}
114
115// OwnedByPrevious checks if the caller of the function is the Realm's owner
116func (o *Ownable) OwnedByPrevious() bool {
117 if o == nil {
118 return false
119 }
120 return runtime.PreviousRealm().Address() == o.owner
121}
122
123// AssertOwnedByPrevious panics if the caller is not the owner
124func (o *Ownable) AssertOwnedByPrevious() {
125 if !o.OwnedByPrevious() {
126 panic(ErrUnauthorized)
127 }
128}