Skip to content

Commit

Permalink
feat(examples): add p/moul/admin
Browse files Browse the repository at this point in the history
Signed-off-by: moul <[email protected]>
  • Loading branch information
moul committed Feb 7, 2025
1 parent b4ebf6c commit dbd4f40
Show file tree
Hide file tree
Showing 3 changed files with 402 additions and 0 deletions.
172 changes: 172 additions & 0 deletions examples/gno.land/p/moul/admin/admin.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package admin

import (
"errors"
"std"
)

const (
AdminTransferEvent = "AdminTransfer"
AdminTypeWallet = "wallet"
AdminTypeContract = "contract"
)

var (
ErrUnauthorized = errors.New("unauthorized")
ErrInvalidAddress = errors.New("invalid address")
)

// PrivilegedAction defines a function that performs a privileged action.
type PrivilegedAction func()

// ContractAdminHandler defines the interface that contract-based admins must implement.
// This allows privileged actions to be handled asynchronously (or synchronously via a DAO or similar governance system).
type ContractAdminHandler interface {
HandlePrivilegedAction(action PrivilegedAction)
}

// Admin encapsulates an owner and its type. It supports both wallet-based ownership and contract-based (e.g. DAO) ownership.
type Admin struct {
owner std.Address
ownerType string // valid values are "wallet" or "contract"
contractHandler ContractAdminHandler
}

// New creates a new Admin instance with the initial owner set to the current caller (from std.PrevRealm())
// and defaults to a wallet-based admin.
func New() *Admin {
return &Admin{
owner: std.PrevRealm().Addr(),
ownerType: AdminTypeWallet,
}
}

// NewWithAddress creates a new Admin instance with the specified address as the owner.
// The admin type defaults to a wallet.
func NewWithAddress(addr std.Address) *Admin {
return &Admin{
owner: addr,
ownerType: AdminTypeWallet,
}
}

// Owner returns the current admin owner.
func (a *Admin) Owner() std.Address {
if a == nil {
return std.Address("")
}
return a.owner
}

// CallerIsAdmin checks if the caller is the current admin.
func (a *Admin) CallerIsAdmin() bool {
if a == nil {
return false
}
return std.PrevRealm().Addr() == a.owner
}

// AssertCallerIsAdmin panics if the caller is not the admin.
func (a *Admin) AssertCallerIsAdmin() {
if a == nil {
panic(ErrUnauthorized)
}
caller := std.PrevRealm().Addr()
if caller != a.owner {
panic(ErrUnauthorized)
}
}

// TransferToWallet transfers admin rights to a new wallet address.
// It resets any existing contract handler.
func (a *Admin) TransferToWallet(walletAddr std.Address) error {
if !a.CallerIsAdmin() {
return ErrUnauthorized
}
if !walletAddr.IsValid() {
return ErrInvalidAddress
}
prevOwner := a.owner
a.owner = walletAddr
a.ownerType = AdminTypeWallet
a.contractHandler = nil

std.Emit(
AdminTransferEvent,
"from", prevOwner.String(),
"to", walletAddr.String(),
"type", AdminTypeWallet,
)

return nil
}

// TransferToContract transfers admin rights to a contract address that implements ContractAdminHandler.
// This is useful when switching to a DAO-based governance model.
func (a *Admin) TransferToContract(contractAddr std.Address, handler ContractAdminHandler) error {
if !a.CallerIsAdmin() {
return ErrUnauthorized
}
if !contractAddr.IsValid() {
return ErrInvalidAddress
}
prevOwner := a.owner
a.owner = contractAddr
a.ownerType = AdminTypeContract
a.contractHandler = handler

std.Emit(
AdminTransferEvent,
"from", prevOwner.String(),
"to", contractAddr.String(),
"type", AdminTypeContract,
)

return nil
}

// AdminToDo executes a privileged action if the caller is authorized.
// When the admin is a wallet, the action is executed immediately.
// When the admin is a contract (e.g. DAO), the action is passed to the contract's handler
// for asynchronous processing (such as through proposal enqueuing).
func (a *Admin) AdminToDo(action PrivilegedAction) error {
if a == nil {
return ErrUnauthorized
}
caller := std.PrevRealm().Addr()
if caller != a.owner {
return ErrUnauthorized
}

switch a.ownerType {
case AdminTypeWallet:
action()
case AdminTypeContract:
if a.contractHandler == nil {
return ErrUnauthorized
}
a.contractHandler.HandlePrivilegedAction(action)
default:
return ErrUnauthorized
}
return nil
}

// DropAdmin revokes admin rights by setting the owner to an empty address.
// This can be used to disable any admin-specific actions.
func (a *Admin) DropAdmin() error {
if !a.CallerIsAdmin() {
return ErrUnauthorized
}
prevOwner := a.owner
a.owner = ""
a.ownerType = ""
a.contractHandler = nil

std.Emit(
AdminTransferEvent,
"from", prevOwner.String(),
"to", "",
)
return nil
}
Loading

0 comments on commit dbd4f40

Please sign in to comment.