Skip to content

Commit

Permalink
feat: add p/demo/pausable (gnolang#1328)
Browse files Browse the repository at this point in the history
## Description


This PR adds the `Pausable` package to p/demo, allowing realms to have
pausability. It relies on the already existing `Ownable` package for
access control, gnolang#1314.

Inspired by OpenZeppelin's
[Pausable](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.3/contracts/security/Pausable.sol).

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [ ] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>

---------

Co-authored-by: Morgan Bazalgette <morgan@morganbaz.com>
  • Loading branch information
2 people authored and moul committed Nov 14, 2023
1 parent 85f7ac6 commit 688ab0a
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/gno.land/p/demo/pausable/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module gno.land/p/demo/pausable

require gno.land/p/demo/ownable v0.0.0-latest
49 changes: 49 additions & 0 deletions examples/gno.land/p/demo/pausable/pausable.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package pausable

import "gno.land/p/demo/ownable"

type Pausable struct {
*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,
}
}

// IsPaused checks if Pausable is paused
func (p Pausable) IsPaused() bool {
return p.paused
}

// 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
}

p.paused = true
return nil
}

// 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
}

p.paused = false
return nil
}
77 changes: 77 additions & 0 deletions examples/gno.land/p/demo/pausable/pausable_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package pausable

import (
"std"
"testing"

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

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

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

result := New()

if result.paused != false {
t.Fatalf("Expected result to be unpaused, got %t\n", result.paused)
}

if result.Owner() != firstCaller {
t.Fatalf("Expected %s, got %s\n", firstCaller, result.Owner())
}
}

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

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

if result.Owner() != firstCaller {
t.Fatalf("Expected %s, got %s\n", firstCaller, result.Owner())
}
}

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

result := New()
result.Unpause()

if result.IsPaused() {
t.Fatalf("Expected result to be unpaused, got %t\n", result.IsPaused())
}
}

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

result := New()
result.Pause()

if !result.IsPaused() {
t.Fatalf("Expected result to be paused, got %t\n", result.IsPaused())
}
}

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

result := New()

if result.IsPaused() {
t.Fatalf("Expected result to be unpaused, got %t\n", result.IsPaused())
}

result.Pause()

if !result.IsPaused() {
t.Fatalf("Expected result to be paused, got %t\n", result.IsPaused())
}
}

0 comments on commit 688ab0a

Please sign in to comment.