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: improve p/ownable API #2330

Merged
merged 5 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions examples/gno.land/p/demo/ownable/ownable.gno
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"std"
)

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.
type Ownable struct {
Expand All @@ -12,10 +14,14 @@ type Ownable struct {

func New() *Ownable {
return &Ownable{
owner: std.GetOrigCaller(),
owner: std.PrevRealm().Addr(),
}
}

func NewWithAddress(addr std.Address) *Ownable {
return &Ownable{owner: addr}
}

// TransferOwnership transfers ownership of the Ownable struct to a new address
func (o *Ownable) TransferOwnership(newOwner std.Address) error {
err := o.CallerIsOwner()
Expand All @@ -27,7 +33,13 @@ func (o *Ownable) TransferOwnership(newOwner std.Address) error {
return ErrInvalidAddress
}

prevOwner := o.owner
o.owner = newOwner
std.Emit(
OwnershipTransferEvent,
"from", string(prevOwner),
Kouteki marked this conversation as resolved.
Show resolved Hide resolved
"to", string(newOwner),
)
return nil
}

Expand All @@ -40,18 +52,32 @@ func (o *Ownable) DropOwnership() error {
return err
}

prevOwner := o.owner
o.owner = ""

std.Emit(
OwnershipTransferEvent,
thehowl marked this conversation as resolved.
Show resolved Hide resolved
"from", string(prevOwner),
"to", "",
)

return nil
}

func (o Ownable) Owner() std.Address {
return o.owner
}

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

func (o *Ownable) Owner() std.Address {
return o.owner
func (o Ownable) AssertCallerIsOwner() {
if std.PrevRealm().Addr() != o.owner {
panic(ErrUnauthorized)
}
}
58 changes: 36 additions & 22 deletions examples/gno.land/p/demo/ownable/ownable_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -11,57 +11,69 @@ var (
)

func TestNew(t *testing.T) {
std.TestSetOrigCaller(firstCaller)
std.TestSetRealm(std.NewUserRealm(firstCaller))
std.TestSetOrigCaller(firstCaller) // TODO(bug): should not be needed

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

func TestOwner(t *testing.T) {
std.TestSetOrigCaller(firstCaller)
func TestNewWithAddress(t *testing.T) {
o := NewWithAddress(firstCaller)

got := o.Owner()
if firstCaller != got {
t.Fatalf("Expected %s, got: %s", firstCaller, got)
}
}

result := New()
resultOwner := result.Owner()
func TestOwner(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(firstCaller))
leohhhn marked this conversation as resolved.
Show resolved Hide resolved

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

func TestTransferOwnership(t *testing.T) {
std.TestSetOrigCaller(firstCaller)
std.TestSetRealm(std.NewUserRealm(firstCaller))

o := New()

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

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

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

o := New()
unauthorizedCaller := secondCaller

std.TestSetOrigCaller(unauthorizedCaller)
std.TestSetRealm(std.NewUserRealm(unauthorizedCaller))
std.TestSetOrigCaller(unauthorizedCaller) // TODO(bug): should not be needed

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

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

o := New()

Expand All @@ -72,18 +84,20 @@ func TestDropOwnership(t *testing.T) {

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

// Errors

func TestErrUnauthorized(t *testing.T) {
std.TestSetOrigCaller(firstCaller)
std.TestSetRealm(std.NewUserRealm(firstCaller))
std.TestSetOrigCaller(firstCaller) // TODO(bug): should not be needed

o := New()

std.TestSetOrigCaller(secondCaller)
std.TestSetRealm(std.NewUserRealm(secondCaller))
std.TestSetOrigCaller(secondCaller) // TODO(bug): should not be needed

err := o.TransferOwnership(firstCaller)
if err != ErrUnauthorized {
Expand All @@ -97,7 +111,7 @@ func TestErrUnauthorized(t *testing.T) {
}

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

o := New()

Expand Down
Loading