Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

rbac source pure

Package rbac provides a simple address-based Role-Based Access Control (RBAC) system for Gno smart contracts. It enab...

Readme View source

RBAC

Role-Based Access Control package for Gno smart contracts.

Overview

RBAC system enabling dynamic role management with address-based authorization and two-step ownership transfer.

Features

  • Dynamic role registration with address assignment
  • Address-based authorization checks
  • Two-step ownership transfer (Ownable2Step pattern)
  • System role protection (cannot be removed)
  • Runtime role address updates

Core API

 1// Create RBAC manager
 2func New() *RBAC
 3func NewRBACWithAddress(addr address) *RBAC
 4
 5// Role management
 6func (rb *RBAC) RegisterRole(roleName string, addr address) error
 7func (rb *RBAC) UpdateRoleAddress(roleName string, addr address) error
 8func (rb *RBAC) RemoveRole(roleName string) error
 9
10// Authorization
11func (rb *RBAC) IsAuthorized(roleName string, addr address) bool
12
13// Role queries
14func (rb *RBAC) GetRoleAddress(roleName string) (address, error)
15func (rb *RBAC) GetAllRoleAddresses() map[string]address
16
17// Ownership management
18func (rb *RBAC) Owner() address
19func (rb *RBAC) PendingOwner() address
20func (rb *RBAC) TransferOwnershipBy(newOwner, caller address) error
21func (rb *RBAC) AcceptOwnershipBy(addr address) error
22func (rb *RBAC) DropOwnershipBy(addr address) error

Usage

 1// Create manager with owner
 2manager := rbac.NewRBACWithAddress(adminAddr)
 3
 4// Register role with address
 5err := manager.RegisterRole("editor", editorAddr)
 6if err != nil {
 7    // handle error
 8}
 9
10// Check authorization
11if manager.IsAuthorized("editor", callerAddr) {
12    // caller is authorized as editor
13}
14
15// Update role address
16err = manager.UpdateRoleAddress("editor", newEditorAddr)
17
18// Get role address
19addr, err := manager.GetRoleAddress("editor")

System Roles

Predefined system roles that cannot be removed:

  • admin, governance, devops
  • pool, position, router, staker
  • emission, launchpad, protocol_fee
  • gov_staker, xgns, community_pool

Errors

Error Description
ErrInvalidRoleName Role name is empty or whitespace-only
ErrRoleAlreadyExists Role already registered
ErrRoleDoesNotExist Role not found
ErrCannotRemoveSystemRole Cannot remove system role
ErrInvalidAddress Invalid address format
ErrUnauthorized Caller is not owner
ErrNoPendingOwner No pending owner
ErrPendingUnauthorized Caller is not pending owner

Security

  • Address-based role authorization
  • Two-step ownership transfer prevents accidental transfers
  • System roles protected from removal
  • Role name validation (no empty/whitespace names)

Overview

Package rbac provides a simple address-based Role-Based Access Control (RBAC) system for Gno smart contracts. It enables dynamic registration, update, and removal of roles with assigned addresses.

## Overview

The RBAC package provides a manager that maintains an internal registry of roles. Each role is identified by a unique name and is associated with a single address. Authorization is performed by checking if a given address matches the role's assigned address.

Key components of this package include:

  1. **Role**: Represents a role with a name and an assigned address.
  2. **RBAC Manager**: The core type (RBAC) that manages role registration, address assignment, authorization verification, and role removal.
  3. **Ownable2Step**: Provides two-step ownership transfer functionality integrated into the RBAC manager.

## Key Features

  • **Dynamic Role Management**: Roles can be registered, updated, and removed at runtime without requiring contract redeployment.
  • **Address-Based Authorization**: Each role is associated with a single address, and authorization is verified by address matching.
  • **System Roles**: Predefined system roles (admin, devops, pool, etc.) that cannot be removed to ensure system integrity.
  • **Two-Step Ownership Transfer**: Built-in secure ownership transfer mechanism requiring explicit acceptance by the new owner.
  • **Encapsulation**: Internal state (roles registry) is encapsulated within the RBAC manager, preventing unintended external modifications.

## Workflow

Typical usage of the RBAC package includes the following steps:

  1. **Initialization**: Create a new RBAC manager using `New()` or `NewRBACWithAddress(addr)`.
  2. **Role Registration**: Register roles using `RegisterRole(roleName, address)`.
  3. **Authorization Check**: Verify if an address is authorized for a role using `IsAuthorized(roleName, address)`.
  4. **Role Management**: Update role addresses with `UpdateRoleAddress` or remove non-system roles with `RemoveRole`.

## Example Usage

The following example demonstrates how to use the RBAC package:

```gno package main

import (

Example
1"gno.land/p/gnoswap/rbac"

)

Example
 1func main() {
 2    // Create a new RBAC manager (origin caller becomes owner)
 3    manager := rbac.New()
 4
 5    // Define example addresses
 6    adminAddr := address("g1...")
 7    userAddr  := address("g1...")
 8
 9    // Register an "admin" role with adminAddr
10    if err := manager.RegisterRole("admin", adminAddr); err != nil {
11        panic(err)
12    }
13
14    // Register a custom "editor" role with userAddr
15    if err := manager.RegisterRole("editor", userAddr); err != nil {
16        panic(err)
17    }
18
19    // Check if adminAddr is authorized for the "admin" role
20    if manager.IsAuthorized("admin", adminAddr) {
21        println("Admin access granted")
22    }
23
24    // Check if userAddr is authorized for the "admin" role
25    if !manager.IsAuthorized("admin", userAddr) {
26        println("User does not have admin access")
27    }
28
29    // Update the editor role to a different address
30    newEditorAddr := address("g1...")
31    if err := manager.UpdateRoleAddress("editor", newEditorAddr); err != nil {
32        panic(err)
33    }
34
35    // Get all role addresses
36    allRoles := manager.GetAllRoleAddresses()
37    for roleName, addr := range allRoles {
38        println(roleName, "->", addr.String())
39    }
40}

```

## System Roles

The package defines several system roles that cannot be removed:

  • admin: System administrator role
  • devops: DevOps operations role
  • community_pool: Community pool management role
  • governance: Governance system role
  • gov_staker: Governance staker role
  • xgns: xGNS token role
  • pool: Pool management role
  • position: Position management role
  • router: Router role
  • staker: Staker role
  • emission: Emission management role
  • launchpad: Launchpad role
  • protocol_fee: Protocol fee management role

## Error Handling

The package defines several error types:

- ErrRoleAlreadyExists: Attempting to register a role that already exists. - ErrRoleDoesNotExist: Attempting to access or modify a non-existent role. - ErrCannotRemoveSystemRole: Attempting to remove a system role. - ErrInvalidAddress: Providing an invalid or empty address. - ErrUnauthorized: Caller is not the owner when owner permission is required. - ErrNoPendingOwner: Attempting to accept ownership when no transfer is pending. - ErrPendingUnauthorized: Caller is not the pending owner when accepting ownership.

## Ownership Management

The RBAC manager includes built-in two-step ownership transfer functionality:

  1. Current owner calls TransferOwnershipBy to initiate transfer.
  2. New owner calls AcceptOwnershipBy to complete the transfer.
  3. Owner can drop ownership entirely using DropOwnershipBy.

## Limitations and Considerations

  • Each role can only have one assigned address. For multi-address authorization, consider creating multiple roles or implementing a wrapper.
  • System roles are protected and cannot be removed to ensure system stability.
  • Address validation checks for empty strings and calls IsValid() method.

Package rbac is intended for use in Gno smart contracts requiring simple, address-based access control with role management capabilities.

Constants 3

const ErrNoPendingOwner, ErrUnauthorized, ErrPendingUnauthorized, ErrInvalidAddress, ErrInvalidRoleName, ErrRoleDoesNotExist, ErrRoleAlreadyExists, ErrCannotRemoveSystemRole

 1const (
 2	ErrNoPendingOwner      = "no pending owner"
 3	ErrUnauthorized        = "caller is not owner"
 4	ErrPendingUnauthorized = "caller is not pending owner"
 5	ErrInvalidAddress      = "invalid address"
 6
 7	ErrInvalidRoleName        = "invalid role name"
 8	ErrRoleDoesNotExist       = "role does not exist"
 9	ErrRoleAlreadyExists      = "role already exists"
10	ErrCannotRemoveSystemRole = "cannot remove system role"
11)
source

const ROLE_ADMIN, ROLE_DEVOPS, ROLE_COMMUNITY_POOL, ROLE_GOVERNANCE, ROLE_GOV_STAKER, ROLE_XGNS, ROLE_POOL, ROLE_POSITION, ROLE_ROUTER, ROLE_STAKER, ROLE_EMISSION, ROLE_LAUNCHPAD, ROLE_PROTOCOL_FEE

 1const (
 2	ROLE_ADMIN          SystemRole = "admin"
 3	ROLE_DEVOPS         SystemRole = "devops"
 4	ROLE_COMMUNITY_POOL SystemRole = "community_pool"
 5	ROLE_GOVERNANCE     SystemRole = "governance"
 6	ROLE_GOV_STAKER     SystemRole = "gov_staker"
 7	ROLE_XGNS           SystemRole = "xgns"
 8	ROLE_POOL           SystemRole = "pool"
 9	ROLE_POSITION       SystemRole = "position"
10	ROLE_ROUTER         SystemRole = "router"
11	ROLE_STAKER         SystemRole = "staker"
12	ROLE_EMISSION       SystemRole = "emission"
13	ROLE_LAUNCHPAD      SystemRole = "launchpad"
14	ROLE_PROTOCOL_FEE   SystemRole = "protocol_fee"
15)
source

Functions 3

func IsSystemRole

1func IsSystemRole(roleName string) bool
source

IsSystemRole returns true if roleName is a system role.

func NewRBACWithAddress

1func NewRBACWithAddress(addr address) *RBAC
source

NewRBACWithAddress creates a new RBAC instance with addr as owner.

func NewRole

1func NewRole(roleName string, addr address) *Role
source

NewRole creates a new Role instance with roleName.

Types 4

type Ownable2Step

struct
1type Ownable2Step struct {
2	owner        address
3	pendingOwner address
4}
source

Ownable2Step implements a two-step ownership transfer mechanism. It requires the new owner to explicitly accept ownership before the transfer is completed, preventing accidental transfers to incorrect addresses.

Note: This package does not verify callers. Consuming realms must extract the actual caller from the live realm context and pass it to these methods.

Methods on Ownable2Step

func AcceptOwnershipBy

method on Ownable2Step
1func (o *Ownable2Step) AcceptOwnershipBy(caller address) error
source

AcceptOwnershipBy completes the ownership transfer. Must be called by the pending owner.

Errors:

  • ErrNoPendingOwner: no ownership transfer is pending
  • ErrPendingUnauthorized: caller is not the pending owner

func DropOwnershipBy

method on Ownable2Step
1func (o *Ownable2Step) DropOwnershipBy(caller address) error
source

DropOwnershipBy removes the owner, disabling all owner-only actions. This is irreversible - when ownership is dropped, no future owner-only operations can be performed.

Errors:

  • ErrUnauthorized: caller is not the current owner

func IsOwner

method on Ownable2Step
1func (o *Ownable2Step) IsOwner(caller address) bool
source

IsOwner returns true if the origin caller is the current owner.

func IsPendingOwner

method on Ownable2Step
1func (o *Ownable2Step) IsPendingOwner(caller address) bool
source

IsPendingOwner returns true if the origin caller is the pending owner.

func Owner

method on Ownable2Step
1func (o *Ownable2Step) Owner() address
source

Owner returns the current owner address. Returns empty address if ownership has been dropped.

func PendingOwner

method on Ownable2Step
1func (o *Ownable2Step) PendingOwner() address
source

PendingOwner returns the pending owner address during ownership transfer. Returns empty address if no transfer is pending.

func TransferOwnershipBy

method on Ownable2Step
1func (o *Ownable2Step) TransferOwnershipBy(newOwner, caller address) error
source

TransferOwnershipBy initiates ownership transfer by setting newOwner as pending owner. The newOwner must call AcceptOwnershipBy to complete the transfer.

Errors:

  • ErrUnauthorized: caller is not the current owner
  • ErrInvalidAddress: newOwner is empty or has an invalid format

type RBAC

struct
1type RBAC struct {
2	ownable *Ownable2Step
3	// roles maps role names to their respective `Role` objects
4	roles map[string]*Role
5}
source

RBAC encapsulates and manages roles and their permissions. It combines role management with two-step ownership transfer functionality.

Methods on RBAC

func AcceptOwnershipBy

method on RBAC
1func (rb *RBAC) AcceptOwnershipBy(addr address) error
source

AcceptOwnershipBy completes the ownership transfer process. Must be called by the pending owner.

Errors:

  • `ErrNoPendingOwner`: no ownership transfer is pending
  • `ErrPendingUnauthorized`: addr is not the pending owner

func DropOwnershipBy

method on RBAC
1func (rb *RBAC) DropOwnershipBy(addr address) error
source

DropOwnershipBy removes the owner, effectively disabling owner-only actions. This is irreversible and will prevent any future owner-only operations.

Errors:

  • `ErrUnauthorized`: addr is not the current owner

func GetAllRoleAddresses

method on RBAC
1func (rb *RBAC) GetAllRoleAddresses() map[string]address
source

GetAllRoleAddresses returns a map of all role names to their assigned addresses.

func GetRoleAddress

method on RBAC
1func (rb *RBAC) GetRoleAddress(roleName string) (address, error)
source

GetRoleAddress returns the address assigned to roleName.

Errors:

  • `ErrRoleDoesNotExist`: the specified role does not exist in the RBAC system

func IsAuthorized

method on RBAC
1func (rb *RBAC) IsAuthorized(roleName string, addr address) bool
source

IsAuthorized checks if addr has the specified roleName. Returns false if the role does not exist.

func Owner

method on RBAC
1func (rb *RBAC) Owner() address
source

Owner returns the current owner address.

func PendingOwner

method on RBAC
1func (rb *RBAC) PendingOwner() address
source

PendingOwner returns the pending owner address during ownership transfer.

func RegisterRole

method on RBAC
1func (rb *RBAC) RegisterRole(roleName string, addr address) error
source

RegisterRole registers a new role with given role name and address.

Errors: `RegisterRole` returns an error in the following situations:

  • `ErrInvalidRoleName`: role name is an empty string or contains only whitespace
  • `ErrRoleAlreadyExists`: the role to be registered already exists in rbac. Since system roles are registered through `initRbac`, attempting to register a new role with a system role name will return an `ErrRoleAlreadyExists` error.

func RemoveRole

method on RBAC
1func (rb *RBAC) RemoveRole(roleName string) error
source

RemoveRole removes roleName from the RBAC system.

Errors:

  • `ErrInvalidRoleName`: role name is an empty string or contains only whitespace
  • `ErrRoleDoesNotExist`: the specified role does not exist in the RBAC system
  • `ErrCannotRemoveSystemRole`: attempting to remove a system role (e.g., admin, governance, pool, etc.)

func TransferOwnershipBy

method on RBAC
1func (rb *RBAC) TransferOwnershipBy(newOwner, caller address) error
source

TransferOwnershipBy initiates the two-step ownership transfer process. The newOwner must call AcceptOwnershipBy to complete the transfer.

Errors:

  • `ErrUnauthorized`: caller is not the current owner
  • `ErrInvalidAddress`: newOwner is empty or has an invalid format

func UpdateRoleAddress

method on RBAC
1func (rb *RBAC) UpdateRoleAddress(roleName string, addr address) error
source

UpdateRoleAddress assigns addr to roleName.

Errors:

  • `ErrInvalidRoleName`: role name is an empty string or contains only whitespace
  • `ErrRoleDoesNotExist`: the specified role does not exist in the RBAC system
  • `ErrInvalidAddress`: addr is empty or has an invalid format

type Role

struct
1type Role struct {
2	// name represents the role's identifier
3	name    string
4	address address
5}
source

Role represents a role with a name and an assigned address.

Methods on Role

func Address

method on Role
1func (r *Role) Address() address
source

Address returns the address assigned to this role. Returns empty address if no address is assigned.

func IsAuthorized

method on Role
1func (r *Role) IsAuthorized(addr address) bool
source

IsAuthorized returns true if addr matches the role's assigned address.

func IsEmpty

method on Role
1func (r *Role) IsEmpty() bool
source

IsEmpty returns true if no address is assigned to this role.

func Name

method on Role
1func (r *Role) Name() string
source

Name returns the role's name.

type SystemRole

ident
1type SystemRole string
source

SystemRole represents a predefined system role that cannot be removed.

Methods on SystemRole

func String

method on SystemRole
1func (r SystemRole) String() string
source

String returns the string representation of the SystemRole. Returns "Unknown" if the role is not a valid system role.

Imports 3

  • chain stdlib
  • errors stdlib
  • strings stdlib

Source Files 8