-
Notifications
You must be signed in to change notification settings - Fork 391
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: moul <[email protected]>
- Loading branch information
Showing
3 changed files
with
402 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.