Skip to content

Commit

Permalink
chore(examples): modify pausable (#3628)
Browse files Browse the repository at this point in the history
## Description

Prevously, the `pausable` object embedded the `ownable` object directly,
and with the intended usage of both packages being the following,
`ownable` functions were being duplicated:

```go
var (
	Ownable = ownable.NewWithAddress(std.Address("xyz"))
	Pausable = pausable.NewFromOwnable(Ownable)
)
```

This PR names the `ownable` inside `pausable` as a private field and
exposes a getter in case someone needs it for some reason. It also
removes the `New()` function, which doesn't make too much sense right
now as the pausable needs to be paired with `ownable` - this might
change later but for now this should be the way.

---------

Signed-off-by: moul <[email protected]>
Co-authored-by: moul <[email protected]>
  • Loading branch information
leohhhn and moul authored Feb 2, 2025
1 parent 627eab2 commit 01abd50
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 44 deletions.
18 changes: 14 additions & 4 deletions examples/gno.land/p/demo/ownable/ownable.gno
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,28 @@ func (o *Ownable) DropOwnership() error {
}

// Owner returns the owner address from Ownable
func (o Ownable) Owner() std.Address {
func (o *Ownable) Owner() std.Address {
if o == nil {
return std.Address("")
}
return o.owner
}

// CallerIsOwner checks if the caller of the function is the Realm's owner
func (o Ownable) CallerIsOwner() bool {
func (o *Ownable) CallerIsOwner() bool {
if o == nil {
return false
}
return std.PrevRealm().Addr() == o.owner
}

// AssertCallerIsOwner panics if the caller is not the owner
func (o Ownable) AssertCallerIsOwner() {
if std.PrevRealm().Addr() != o.owner {
func (o *Ownable) AssertCallerIsOwner() {
if o == nil {
panic(ErrUnauthorized)
}
caller := std.PrevRealm().Addr()
if caller != o.owner {
panic(ErrUnauthorized)
}
}
48 changes: 48 additions & 0 deletions examples/gno.land/p/demo/ownable/ownable_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,51 @@ func TestErrInvalidAddress(t *testing.T) {
err = o.TransferOwnership("10000000001000000000100000000010000000001000000000")
uassert.ErrorContains(t, err, ErrInvalidAddress.Error())
}

func TestAssertCallerIsOwner(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))
std.TestSetOrigCaller(alice)

o := New()

// Should not panic when caller is owner
o.AssertCallerIsOwner()

// Should panic when caller is not owner
std.TestSetRealm(std.NewUserRealm(bob))
std.TestSetOrigCaller(bob)

defer func() {
r := recover()
if r == nil {
t.Error("expected panic but got none")
}
if r != ErrUnauthorized {
t.Errorf("expected ErrUnauthorized but got %v", r)
}
}()
o.AssertCallerIsOwner()
}

func TestNilReceiver(t *testing.T) {
var o *Ownable

owner := o.Owner()
if owner != std.Address("") {
t.Errorf("expected empty address but got %v", owner)
}

isOwner := o.CallerIsOwner()
uassert.False(t, isOwner)

defer func() {
r := recover()
if r == nil {
t.Error("expected panic but got none")
}
if r != ErrUnauthorized {
t.Errorf("expected ErrUnauthorized but got %v", r)
}
}()
o.AssertCallerIsOwner()
}
27 changes: 12 additions & 15 deletions examples/gno.land/p/demo/pausable/pausable.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,15 @@ import (
)

type Pausable struct {
*ownable.Ownable
o *ownable.Ownable
paused bool
}

// New returns a new Pausable struct with non-paused state as default
func New() *Pausable {
return &Pausable{
Ownable: ownable.New(),
paused: false,
}
}

// NewFromOwnable is the same as New, but with a pre-existing top-level ownable
func NewFromOwnable(ownable *ownable.Ownable) *Pausable {
return &Pausable{
Ownable: ownable,
paused: false,
o: ownable,
paused: false,
}
}

Expand All @@ -34,24 +26,29 @@ 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 !p.CallerIsOwner() {
if !p.o.CallerIsOwner() {
return ownable.ErrUnauthorized
}

p.paused = true
std.Emit("Paused", "account", p.Owner().String())
std.Emit("Paused", "account", p.o.Owner().String())

return nil
}

// Unpause sets the state of Pausable to false, meaning all pausable functions are resumed
func (p *Pausable) Unpause() error {
if !p.CallerIsOwner() {
if !p.o.CallerIsOwner() {
return ownable.ErrUnauthorized
}

p.paused = false
std.Emit("Unpaused", "account", p.Owner().String())
std.Emit("Unpaused", "account", p.o.Owner().String())

return nil
}

// Ownable returns the underlying ownable
func (p *Pausable) Ownable() *ownable.Ownable {
return p.o
}
42 changes: 17 additions & 25 deletions examples/gno.land/p/demo/pausable/pausable_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,49 @@ import (
"testing"

"gno.land/p/demo/ownable"
"gno.land/p/demo/uassert"
"gno.land/p/demo/urequire"
)

var (
firstCaller = std.Address("g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de")
secondCaller = std.Address("g127jydsh6cms3lrtdenydxsckh23a8d6emqcvfa")
firstCaller = std.Address("g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de")
o = ownable.NewWithAddress(firstCaller)
)

func TestNew(t *testing.T) {
std.TestSetOrigCaller(firstCaller)

result := New()

urequire.False(t, result.paused, "Expected result to be unpaused")
urequire.Equal(t, firstCaller.String(), result.Owner().String())
}

func TestNewFromOwnable(t *testing.T) {
std.TestSetOrigCaller(firstCaller)
o := ownable.New()

std.TestSetOrigCaller(secondCaller)
result := NewFromOwnable(o)

urequire.Equal(t, firstCaller.String(), result.Owner().String())
urequire.Equal(t, firstCaller.String(), result.Ownable().Owner().String())
}

func TestSetUnpaused(t *testing.T) {
std.TestSetOrigCaller(firstCaller)
result := NewFromOwnable(o)

result := New()
result.Unpause()

urequire.False(t, result.IsPaused(), "Expected result to be unpaused")
uassert.False(t, result.IsPaused(), "Expected result to be unpaused")
}

func TestSetPaused(t *testing.T) {
std.TestSetOrigCaller(firstCaller)
result := NewFromOwnable(o)

result := New()
result.Pause()

urequire.True(t, result.IsPaused(), "Expected result to be paused")
uassert.True(t, result.IsPaused(), "Expected result to be paused")
}

func TestIsPaused(t *testing.T) {
std.TestSetOrigCaller(firstCaller)

result := New()
result := NewFromOwnable(o)
urequire.False(t, result.IsPaused(), "Expected result to be unpaused")

std.TestSetOrigCaller(firstCaller)
result.Pause()
urequire.True(t, result.IsPaused(), "Expected result to be paused")
uassert.True(t, result.IsPaused(), "Expected result to be paused")
}

func TestOwnable(t *testing.T) {
result := NewFromOwnable(o)

uassert.Equal(t, result.Ownable().Owner(), o.Owner())
}

0 comments on commit 01abd50

Please sign in to comment.