Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add p/demo/ownable #1314

Merged
merged 20 commits into from
Nov 2, 2023
8 changes: 8 additions & 0 deletions examples/gno.land/p/demo/ownable/errors.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ownable

import "errors"

var (
ErrUnauthorized = errors.New("unauthorized; caller is not owner")
ErrInvalidAddress = errors.New("new owner address is invalid")
)
60 changes: 60 additions & 0 deletions examples/gno.land/p/demo/ownable/ownable.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package ownable

import (
"std"
)

// 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.
type Ownable struct {
owner std.Address
}

func New() *Ownable {
o := Ownable{}
caller := std.GetOrigCaller()
o.setOwner(caller)
return &o
}
leohhhn marked this conversation as resolved.
Show resolved Hide resolved

// TransferOwnership transfers ownership of the Ownable struct to a new address
func (o *Ownable) TransferOwnership(newOwner std.Address) error {
if !o.CallerIsOwner() {
return ErrUnauthorized
}

if !newOwner.IsValid() {
return ErrInvalidAddress
}

o.setOwner(newOwner)
return nil
}

// DropOwnership Removes the owner, effectively disabling any owner-related actions
leohhhn marked this conversation as resolved.
Show resolved Hide resolved
// 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 {
if !o.CallerIsOwner() {
return ErrUnauthorized
}

o.owner = ""
return nil
}

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

func (o *Ownable) GetOwner() std.Address {
leohhhn marked this conversation as resolved.
Show resolved Hide resolved
return o.owner
}

func (o *Ownable) setOwner(newOwner std.Address) {
o.owner = newOwner
}
leohhhn marked this conversation as resolved.
Show resolved Hide resolved
115 changes: 115 additions & 0 deletions examples/gno.land/p/demo/ownable/ownable_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package ownable

import (
"std"
"testing"
)

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

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

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

func TestGetOwner(t *testing.T) {
leohhhn marked this conversation as resolved.
Show resolved Hide resolved
std.TestSetOrigCaller(firstCaller)

result := New()
resultOwner := result.GetOwner()

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

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

err := o.TransferOwnership(secondCaller)
if err != nil {
t.Fatalf("TransferOwnership failed, %v", err)
}

result := o.GetOwner()
if secondCaller != result {
t.Fatalf("Expected: %s, got: %s\n", secondCaller, result)
}
}

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

o := New()
unauthorizedCaller := secondCaller

std.TestSetOrigCaller(unauthorizedCaller)

if o.CallerIsOwner() {
t.Fatalf("Expected: %s to not be owner\n", unauthorizedCaller)
}
}

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

o := New()

err := o.DropOwnership()
if err != nil {
t.Fatalf("DropOwnership failed, %v", err)
}

owner := o.GetOwner()
if owner != "" {
t.Fatalf("Expected owner to be empty, not %s\n", owner)
}
}

// TODO add embedded Tests?
leohhhn marked this conversation as resolved.
Show resolved Hide resolved

// Errors

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

o := New()

std.TestSetOrigCaller(secondCaller)

err := o.TransferOwnership(firstCaller)
if err != ErrUnauthorized { // TODO errors.Is doesnt work
leohhhn marked this conversation as resolved.
Show resolved Hide resolved
t.Fatalf("Shoud've been ErrUnauthorized, was %v", err)
leohhhn marked this conversation as resolved.
Show resolved Hide resolved
}

err = o.DropOwnership()
if err != ErrUnauthorized {
t.Fatalf("Shoud've been ErrUnauthorized, was %v", err)
}
}

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

o := New()

err := o.TransferOwnership("")

if err != ErrInvalidAddress {
t.Fatalf("Shoud've been ErrInvalidAddress, was %v", err)
}

err = o.TransferOwnership("10000000001000000000100000000010000000001000000000")
if err != ErrInvalidAddress {
t.Fatalf("Shoud've been ErrInvalidAddress, was %v", err)
}
}
Loading