diff --git a/examples/gno.land/p/demo/memeland/memeland.gno b/examples/gno.land/p/demo/memeland/memeland.gno index 9c302ca365b..38f42239bec 100644 --- a/examples/gno.land/p/demo/memeland/memeland.gno +++ b/examples/gno.land/p/demo/memeland/memeland.gno @@ -160,8 +160,8 @@ func (m *Memeland) RemovePost(id string) string { panic("id cannot be empty") } - if err := m.CallerIsOwner(); err != nil { - panic(err) + if !m.CallerIsOwner() { + panic(ownable.ErrUnauthorized) } for i, post := range m.Posts { diff --git a/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable.gno b/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable.gno index f9f0ea15dd9..95bd2ac4959 100644 --- a/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable.gno +++ b/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable.gno @@ -41,7 +41,7 @@ func NewAuthorizableWithAddress(addr std.Address) *Authorizable { } func (a *Authorizable) AddToAuthList(addr std.Address) error { - if err := a.CallerIsOwner(); err != nil { + if !a.CallerIsOwner() { return ErrNotSuperuser } @@ -55,7 +55,7 @@ func (a *Authorizable) AddToAuthList(addr std.Address) error { } func (a *Authorizable) DeleteFromAuthList(addr std.Address) error { - if err := a.CallerIsOwner(); err != nil { + if !a.CallerIsOwner() { return ErrNotSuperuser } diff --git a/examples/gno.land/p/demo/ownable/ownable.gno b/examples/gno.land/p/demo/ownable/ownable.gno index 48a1c15fffa..f565e27c0f2 100644 --- a/examples/gno.land/p/demo/ownable/ownable.gno +++ b/examples/gno.land/p/demo/ownable/ownable.gno @@ -6,6 +6,7 @@ const OwnershipTransferEvent = "OwnershipTransfer" // Ownable 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 type Ownable struct { owner std.Address } @@ -24,9 +25,8 @@ func NewWithAddress(addr std.Address) *Ownable { // TransferOwnership transfers ownership of the Ownable struct to a new address func (o *Ownable) TransferOwnership(newOwner std.Address) error { - err := o.CallerIsOwner() - if err != nil { - return err + if !o.CallerIsOwner() { + return ErrUnauthorized } if !newOwner.IsValid() { @@ -48,9 +48,8 @@ func (o *Ownable) TransferOwnership(newOwner std.Address) error { // Top-level usage: disables all only-owner actions/functions, // Embedded usage: behaves like a burn functionality, removing the owner from the struct func (o *Ownable) DropOwnership() error { - err := o.CallerIsOwner() - if err != nil { - return err + if !o.CallerIsOwner() { + return ErrUnauthorized } prevOwner := o.owner @@ -71,12 +70,8 @@ func (o Ownable) Owner() std.Address { } // CallerIsOwner checks if the caller of the function is the Realm's owner -func (o Ownable) CallerIsOwner() error { - if std.PrevRealm().Addr() == o.owner { - return nil - } - - return ErrUnauthorized +func (o Ownable) CallerIsOwner() bool { + return std.PrevRealm().Addr() == o.owner } // AssertCallerIsOwner panics if the caller is not the owner diff --git a/examples/gno.land/p/demo/ownable/ownable_test.gno b/examples/gno.land/p/demo/ownable/ownable_test.gno index dee40fa6e1d..f58af9642c6 100644 --- a/examples/gno.land/p/demo/ownable/ownable_test.gno +++ b/examples/gno.land/p/demo/ownable/ownable_test.gno @@ -6,6 +6,7 @@ import ( "gno.land/p/demo/testutils" "gno.land/p/demo/uassert" + "gno.land/p/demo/urequire" ) var ( @@ -19,18 +20,14 @@ func TestNew(t *testing.T) { o := New() got := o.Owner() - if alice != got { - t.Fatalf("Expected %s, got: %s", alice, got) - } + uassert.Equal(t, got, alice) } func TestNewWithAddress(t *testing.T) { o := NewWithAddress(alice) got := o.Owner() - if alice != got { - t.Fatalf("Expected %s, got: %s", alice, got) - } + uassert.Equal(t, got, alice) } func TestTransferOwnership(t *testing.T) { @@ -39,14 +36,11 @@ func TestTransferOwnership(t *testing.T) { o := New() err := o.TransferOwnership(bob) - if err != nil { - t.Fatalf("TransferOwnership failed, %v", err) - } + urequire.NoError(t, err) got := o.Owner() - if bob != got { - t.Fatalf("Expected: %s, got: %s", bob, got) - } + + uassert.Equal(t, got, bob) } func TestCallerIsOwner(t *testing.T) { @@ -58,8 +52,7 @@ func TestCallerIsOwner(t *testing.T) { std.TestSetRealm(std.NewUserRealm(unauthorizedCaller)) std.TestSetOrigCaller(unauthorizedCaller) // TODO(bug): should not be needed - err := o.CallerIsOwner() - uassert.Error(t, err) // XXX: IsError(..., unauthorizedCaller) + uassert.False(t, o.CallerIsOwner()) } func TestDropOwnership(t *testing.T) { @@ -68,7 +61,7 @@ func TestDropOwnership(t *testing.T) { o := New() err := o.DropOwnership() - uassert.NoError(t, err, "DropOwnership failed") + urequire.NoError(t, err, "DropOwnership failed") owner := o.Owner() uassert.Empty(t, owner, "owner should be empty") @@ -85,13 +78,8 @@ func TestErrUnauthorized(t *testing.T) { std.TestSetRealm(std.NewUserRealm(bob)) std.TestSetOrigCaller(bob) // TODO(bug): should not be needed - err := o.TransferOwnership(alice) - if err != ErrUnauthorized { - t.Fatalf("Should've been ErrUnauthorized, was %v", err) - } - - err = o.DropOwnership() - uassert.ErrorContains(t, err, ErrUnauthorized.Error()) + uassert.ErrorContains(t, o.TransferOwnership(alice), ErrUnauthorized.Error()) + uassert.ErrorContains(t, o.DropOwnership(), ErrUnauthorized.Error()) } func TestErrInvalidAddress(t *testing.T) { diff --git a/examples/gno.land/p/demo/pausable/pausable.gno b/examples/gno.land/p/demo/pausable/pausable.gno index e9cce63c1e3..e6a85771fa6 100644 --- a/examples/gno.land/p/demo/pausable/pausable.gno +++ b/examples/gno.land/p/demo/pausable/pausable.gno @@ -34,8 +34,8 @@ func (p Pausable) IsPaused() bool { // Pause sets the state of Pausable to true, meaning all pausable functions are paused func (p *Pausable) Pause() error { - if err := p.CallerIsOwner(); err != nil { - return err + if !p.CallerIsOwner() { + return ownable.ErrUnauthorized } p.paused = true @@ -46,8 +46,8 @@ func (p *Pausable) Pause() error { // Unpause sets the state of Pausable to false, meaning all pausable functions are resumed func (p *Pausable) Unpause() error { - if err := p.CallerIsOwner(); err != nil { - return err + if !p.CallerIsOwner() { + return ownable.ErrUnauthorized } p.paused = false diff --git a/examples/gno.land/p/demo/subscription/lifetime/lifetime.gno b/examples/gno.land/p/demo/subscription/lifetime/lifetime.gno index 8a4c10b687b..be661e70129 100644 --- a/examples/gno.land/p/demo/subscription/lifetime/lifetime.gno +++ b/examples/gno.land/p/demo/subscription/lifetime/lifetime.gno @@ -67,7 +67,7 @@ func (ls *LifetimeSubscription) HasValidSubscription(addr std.Address) error { // UpdateAmount allows the owner of the LifetimeSubscription contract to update the subscription price. func (ls *LifetimeSubscription) UpdateAmount(newAmount int64) error { - if err := ls.CallerIsOwner(); err != nil { + if !ls.CallerIsOwner() { return ErrNotAuthorized } diff --git a/examples/gno.land/p/demo/subscription/recurring/recurring.gno b/examples/gno.land/p/demo/subscription/recurring/recurring.gno index b5277bd716e..8f116009aa6 100644 --- a/examples/gno.land/p/demo/subscription/recurring/recurring.gno +++ b/examples/gno.land/p/demo/subscription/recurring/recurring.gno @@ -90,7 +90,7 @@ func (rs *RecurringSubscription) GetExpiration(addr std.Address) (time.Time, err // UpdateAmount allows the owner of the subscription contract to change the required subscription amount. func (rs *RecurringSubscription) UpdateAmount(newAmount int64) error { - if err := rs.CallerIsOwner(); err != nil { + if !rs.CallerIsOwner() { return ErrNotAuthorized } diff --git a/examples/gno.land/p/n2p5/mgroup/mgroup.gno b/examples/gno.land/p/n2p5/mgroup/mgroup.gno index 0c029401ff7..566d625a003 100644 --- a/examples/gno.land/p/n2p5/mgroup/mgroup.gno +++ b/examples/gno.land/p/n2p5/mgroup/mgroup.gno @@ -44,8 +44,8 @@ func New(ownerAddress std.Address) *ManagedGroup { // AddBackupOwner adds a backup owner to the group by std.Address. // If the caller is not the owner, an error is returned. func (g *ManagedGroup) AddBackupOwner(addr std.Address) error { - if err := g.owner.CallerIsOwner(); err != nil { - return err + if !g.owner.CallerIsOwner() { + return ownable.ErrUnauthorized } if !addr.IsValid() { return ErrInvalidAddress @@ -57,8 +57,8 @@ func (g *ManagedGroup) AddBackupOwner(addr std.Address) error { // RemoveBackupOwner removes a backup owner from the group by std.Address. // The owner cannot be removed. If the caller is not the owner, an error is returned. func (g *ManagedGroup) RemoveBackupOwner(addr std.Address) error { - if err := g.owner.CallerIsOwner(); err != nil { - return err + if !g.owner.CallerIsOwner() { + return ownable.ErrUnauthorized } if !addr.IsValid() { return ErrInvalidAddress @@ -90,8 +90,8 @@ func (g *ManagedGroup) ClaimOwnership() error { // AddMember adds a member to the group by std.Address. // If the caller is not the owner, an error is returned. func (g *ManagedGroup) AddMember(addr std.Address) error { - if err := g.owner.CallerIsOwner(); err != nil { - return err + if !g.owner.CallerIsOwner() { + return ownable.ErrUnauthorized } if !addr.IsValid() { return ErrInvalidAddress @@ -104,8 +104,8 @@ func (g *ManagedGroup) AddMember(addr std.Address) error { // The owner cannot be removed. If the caller is not the owner, // an error is returned. func (g *ManagedGroup) RemoveMember(addr std.Address) error { - if err := g.owner.CallerIsOwner(); err != nil { - return err + if !g.owner.CallerIsOwner() { + return ownable.ErrUnauthorized } if !addr.IsValid() { return ErrInvalidAddress diff --git a/examples/gno.land/r/demo/foo20/foo20.gno b/examples/gno.land/r/demo/foo20/foo20.gno index 97b2e52b94b..5c7d7f12b99 100644 --- a/examples/gno.land/r/demo/foo20/foo20.gno +++ b/examples/gno.land/r/demo/foo20/foo20.gno @@ -17,11 +17,11 @@ import ( var ( Token, privateLedger = grc20.NewToken("Foo", "FOO", 4) UserTeller = Token.CallerTeller() - owner = ownable.NewWithAddress("g1manfred47kzduec920z88wfr64ylksmdcedlf5") // @manfred + Ownable = ownable.NewWithAddress("g1manfred47kzduec920z88wfr64ylksmdcedlf5") // @manfred ) func init() { - privateLedger.Mint(owner.Owner(), 1_000_000*10_000) // @privateLedgeristrator (1M) + privateLedger.Mint(Ownable.Owner(), 1_000_000*10_000) // @privateLedgeristrator (1M) getter := func() *grc20.Token { return Token } grc20reg.Register(getter, "") } @@ -66,13 +66,13 @@ func Faucet() { } func Mint(to pusers.AddressOrName, amount uint64) { - owner.AssertCallerIsOwner() + Ownable.AssertCallerIsOwner() toAddr := users.Resolve(to) checkErr(privateLedger.Mint(toAddr, amount)) } func Burn(from pusers.AddressOrName, amount uint64) { - owner.AssertCallerIsOwner() + Ownable.AssertCallerIsOwner() fromAddr := users.Resolve(from) checkErr(privateLedger.Burn(fromAddr, amount)) } diff --git a/examples/gno.land/r/demo/grc20factory/grc20factory.gno b/examples/gno.land/r/demo/grc20factory/grc20factory.gno index cfd32479f9d..58874409d7f 100644 --- a/examples/gno.land/r/demo/grc20factory/grc20factory.gno +++ b/examples/gno.land/r/demo/grc20factory/grc20factory.gno @@ -120,6 +120,17 @@ func Burn(symbol string, from std.Address, amount uint64) { checkErr(inst.ledger.Burn(from, amount)) } +// instance admin functionality +func DropInstanceOwnership(symbol string) { + inst := mustGetInstance(symbol) + checkErr(inst.admin.DropOwnership()) +} + +func TransferInstanceOwnership(symbol string, newOwner std.Address) { + inst := mustGetInstance(symbol) + checkErr(inst.admin.TransferOwnership(newOwner)) +} + func Render(path string) string { parts := strings.Split(path, "/") c := len(parts) diff --git a/examples/gno.land/r/gnoland/events/administration.gno b/examples/gno.land/r/gnoland/events/administration.gno deleted file mode 100644 index 02914adee69..00000000000 --- a/examples/gno.land/r/gnoland/events/administration.gno +++ /dev/null @@ -1,26 +0,0 @@ -package events - -import ( - "std" - - "gno.land/p/demo/ownable/exts/authorizable" -) - -var ( - su = std.Address("g125em6arxsnj49vx35f0n0z34putv5ty3376fg5") // @leohhhn - auth = authorizable.NewAuthorizableWithAddress(su) -) - -// GetOwner gets the owner of the events realm -func GetOwner() std.Address { - return auth.Owner() -} - -// AddModerator adds a moderator to the events realm -func AddModerator(mod std.Address) { - auth.AssertCallerIsOwner() - - if err := auth.AddToAuthList(mod); err != nil { - panic(err) - } -} diff --git a/examples/gno.land/r/gnoland/events/events.gno b/examples/gno.land/r/gnoland/events/events.gno index baf9ba3d4af..d72638ceaaf 100644 --- a/examples/gno.land/r/gnoland/events/events.gno +++ b/examples/gno.land/r/gnoland/events/events.gno @@ -9,6 +9,7 @@ import ( "strings" "time" + "gno.land/p/demo/ownable/exts/authorizable" "gno.land/p/demo/seqid" "gno.land/p/demo/ufmt" ) @@ -28,6 +29,9 @@ type ( ) var ( + su = std.Address("g125em6arxsnj49vx35f0n0z34putv5ty3376fg5") // @leohhhn + Auth = authorizable.NewAuthorizableWithAddress(su) + events = make(eventsSlice, 0) // sorted idCounter seqid.ID ) @@ -42,7 +46,7 @@ const ( // AddEvent adds auth new event // Start time & end time need to be specified in RFC3339, ie 2024-08-08T12:00:00+02:00 func AddEvent(name, description, link, location, startTime, endTime string) (string, error) { - auth.AssertOnAuthList() + Auth.AssertOnAuthList() if strings.TrimSpace(name) == "" { return "", ErrEmptyName @@ -81,7 +85,7 @@ func AddEvent(name, description, link, location, startTime, endTime string) (str // DeleteEvent deletes an event with auth given ID func DeleteEvent(id string) { - auth.AssertOnAuthList() + Auth.AssertOnAuthList() e, idx, err := GetEventByID(id) if err != nil { @@ -99,7 +103,7 @@ func DeleteEvent(id string) { // It only updates values corresponding to non-empty arguments sent with the call // Note: if you need to update the start time or end time, you need to provide both every time func EditEvent(id string, name, description, link, location, startTime, endTime string) { - auth.AssertOnAuthList() + Auth.AssertOnAuthList() e, _, err := GetEventByID(id) if err != nil { diff --git a/examples/gno.land/r/gnoland/events/rendering.gno b/examples/gno.land/r/gnoland/events/render.gno similarity index 100% rename from examples/gno.land/r/gnoland/events/rendering.gno rename to examples/gno.land/r/gnoland/events/render.gno diff --git a/examples/gno.land/r/gnoland/monit/monit.gno b/examples/gno.land/r/gnoland/monit/monit.gno index 8747ea582b3..be94fbdd2bb 100644 --- a/examples/gno.land/r/gnoland/monit/monit.gno +++ b/examples/gno.land/r/gnoland/monit/monit.gno @@ -20,7 +20,7 @@ var ( lastUpdate time.Time lastCaller std.Address wd = watchdog.Watchdog{Duration: 5 * time.Minute} - owner = ownable.New() // TODO: replace with -> ownable.NewWithAddress... + Ownable = ownable.New() // TODO: replace with -> ownable.NewWithAddress... watchdogDuration = 5 * time.Minute ) @@ -37,9 +37,8 @@ func Incr() int { // Reset resets the realm state. // This function can only be called by the admin. func Reset() { - if owner.CallerIsOwner() != nil { // TODO: replace with owner.AssertCallerIsOwner - panic("unauthorized") - } + Ownable.AssertCallerIsOwner() + counter = 0 lastCaller = std.PrevRealm().Addr() lastUpdate = time.Now() @@ -53,7 +52,3 @@ func Render(_ string) string { counter, lastUpdate, lastCaller, status, ) } - -// TransferOwnership transfers ownership to a new owner. This is a proxy to -// ownable.Ownable.TransferOwnership. -func TransferOwnership(newOwner std.Address) { owner.TransferOwnership(newOwner) } diff --git a/examples/gno.land/r/leon/hof/administration.gno b/examples/gno.land/r/leon/hof/administration.gno deleted file mode 100644 index 4b5b212eddf..00000000000 --- a/examples/gno.land/r/leon/hof/administration.gno +++ /dev/null @@ -1,24 +0,0 @@ -package hof - -import "std" - -// Exposing the ownable & pausable APIs -// Should not be needed as soon as MsgCall supports calling methods on exported variables - -func Pause() error { - return exhibition.Pause() -} - -func Unpause() error { - return exhibition.Unpause() -} - -func GetOwner() std.Address { - return owner.Owner() -} - -func TransferOwnership(newOwner std.Address) { - if err := owner.TransferOwnership(newOwner); err != nil { - panic(err) - } -} diff --git a/examples/gno.land/r/leon/hof/hof.gno b/examples/gno.land/r/leon/hof/hof.gno index 2722c019497..147a0dd1a95 100644 --- a/examples/gno.land/r/leon/hof/hof.gno +++ b/examples/gno.land/r/leon/hof/hof.gno @@ -14,7 +14,10 @@ import ( var ( exhibition *Exhibition - owner *ownable.Ownable + + // Safe objects + Ownable *ownable.Ownable + Pausable *pausable.Pausable ) type ( @@ -23,7 +26,6 @@ type ( description string items *avl.Tree // pkgPath > Item itemsSorted *avl.Tree // same data but sorted, storing pointers - *pausable.Pausable } Item struct { @@ -41,14 +43,14 @@ func init() { itemsSorted: avl.NewTree(), } - owner = ownable.NewWithAddress(std.Address("g125em6arxsnj49vx35f0n0z34putv5ty3376fg5")) - exhibition.Pausable = pausable.NewFromOwnable(owner) + Ownable = ownable.NewWithAddress(std.Address("g125em6arxsnj49vx35f0n0z34putv5ty3376fg5")) + Pausable = pausable.NewFromOwnable(Ownable) } // Register registers your realm to the Hall of Fame // Should be called from within code func Register() { - if exhibition.IsPaused() { + if Pausable.IsPaused() { return } @@ -113,8 +115,8 @@ func Downvote(pkgpath string) { } func Delete(pkgpath string) { - if err := owner.CallerIsOwner(); err != nil { - panic(err) + if !Ownable.CallerIsOwner() { + panic(ownable.ErrUnauthorized.Error()) } i, ok := exhibition.items.Get(pkgpath) diff --git a/examples/gno.land/r/leon/hof/hof_test.gno b/examples/gno.land/r/leon/hof/hof_test.gno index 72e8d2159be..4d6f70eab88 100644 --- a/examples/gno.land/r/leon/hof/hof_test.gno +++ b/examples/gno.land/r/leon/hof/hof_test.gno @@ -12,7 +12,7 @@ import ( const rlmPath = "gno.land/r/gnoland/home" var ( - admin = owner.Owner() + admin = Ownable.Owner() adminRealm = std.NewUserRealm(admin) alice = testutils.TestAddress("alice") ) @@ -27,7 +27,7 @@ func TestRegister(t *testing.T) { // Test register while paused std.TestSetRealm(adminRealm) - Pause() + Pausable.Pause() // Set legitimate caller std.TestSetRealm(std.NewCodeRealm(rlmPath)) @@ -37,7 +37,7 @@ func TestRegister(t *testing.T) { // Unpause std.TestSetRealm(adminRealm) - Unpause() + Pausable.Unpause() // Set legitimate caller std.TestSetRealm(std.NewCodeRealm(rlmPath)) diff --git a/examples/gno.land/r/leon/hof/render.gno b/examples/gno.land/r/leon/hof/render.gno index 0721c7d6e72..868262bedc7 100644 --- a/examples/gno.land/r/leon/hof/render.gno +++ b/examples/gno.land/r/leon/hof/render.gno @@ -80,9 +80,9 @@ func renderDashboard() string { out += "## Dashboard\n\n" out += ufmt.Sprintf("Total submissions: %d\n\n", exhibition.items.Size()) - out += ufmt.Sprintf("Exhibition admin: %s\n\n", owner.Owner().String()) + out += ufmt.Sprintf("Exhibition admin: %s\n\n", Ownable.Owner().String()) - if !exhibition.IsPaused() { + if !Pausable.IsPaused() { out += ufmt.Sprintf("[Pause exhibition](%s)\n\n", txlink.Call("Pause")) } else { out += ufmt.Sprintf("[Unpause exhibition](%s)\n\n", txlink.Call("Unpause")) diff --git a/examples/gno.land/r/sys/users/verify.gno b/examples/gno.land/r/sys/users/verify.gno index a836e84683d..71869fda1a1 100644 --- a/examples/gno.land/r/sys/users/verify.gno +++ b/examples/gno.land/r/sys/users/verify.gno @@ -48,8 +48,8 @@ func VerifyNameByUser(enable bool, address std.Address, name string) bool { // Enable this package. func AdminEnable() { - if err := owner.CallerIsOwner(); err != nil { - panic(err) + if !owner.CallerIsOwner() { + panic(ownable.ErrUnauthorized) } enabled = true @@ -57,8 +57,8 @@ func AdminEnable() { // Disable this package. func AdminDisable() { - if err := owner.CallerIsOwner(); err != nil { - panic(err) + if !owner.CallerIsOwner() { + panic(ownable.ErrUnauthorized) } enabled = false @@ -66,8 +66,8 @@ func AdminDisable() { // AdminUpdateVerifyCall updates the method that verifies the namespace. func AdminUpdateVerifyCall(check VerifyNameFunc) { - if err := owner.CallerIsOwner(); err != nil { - panic(err) + if !owner.CallerIsOwner() { + panic(ownable.ErrUnauthorized) } checkFunc = check @@ -75,8 +75,8 @@ func AdminUpdateVerifyCall(check VerifyNameFunc) { // AdminTransferOwnership transfers the ownership to a new owner. func AdminTransferOwnership(newOwner std.Address) error { - if err := owner.CallerIsOwner(); err != nil { - panic(err) + if !owner.CallerIsOwner() { + panic(ownable.ErrUnauthorized) } return owner.TransferOwnership(newOwner)