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

v1 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 with an explicit owner address.
 2func NewRBACWithAddress(addr address) *RBAC
 3
 4// Role management
 5func (rb *RBAC) RegisterRole(roleName string, addr address) error
 6func (rb *RBAC) UpdateRoleAddress(roleName string, addr address) error
 7func (rb *RBAC) RemoveRole(roleName string) error
 8
 9// Authorization
10func (rb *RBAC) IsAuthorized(roleName string, addr address) bool
11
12// Role queries
13func (rb *RBAC) GetRoleAddress(roleName string) (address, error)
14func (rb *RBAC) GetAllRoleAddresses() map[string]address
15
16// Ownership management
17func (rb *RBAC) Owner() address
18func (rb *RBAC) PendingOwner() address
19func (rb *RBAC) TransferOwnershipBy(newOwner, caller address) error
20func (rb *RBAC) AcceptOwnershipBy(addr address) error
21func (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

Reserved system-role names cannot be removed after they are registered. A new RBAC manager starts with no role entries; register each system role explicitly with its address.

  • 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 a registered system role
ErrInvalidAddress Invalid address for UpdateRoleAddress or ownership transfer; RegisterRole stores its supplied address without validation
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,
  • **System Roles**: Reserved system-role names (admin, devops, pool, etc.) cannot be removed once registered. The constructor does not pre-populate these role entries; callers register their addresses explicitly.
  • **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 with `NewRBACWithAddress(addr)`, passing the intended owner explicitly.
  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/v1"

)

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

```

## System Roles

The package reserves the following system-role names. A new RBAC manager starts with no role entries, so callers must register each role and address explicitly. Once registered, a system role 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 registered system role.
  • ErrInvalidAddress: Providing an invalid address to UpdateRoleAddress or an ownership-transfer method. RegisterRole stores its supplied address without validating it.
  • 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.
  • `RegisterRole` does not validate the supplied address. Address validation is performed by `UpdateRoleAddress` and ownership-transfer methods.

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.

Parameters:

  • roleName: Exact string key to check against the reserved system-role registry.

Returns:

  • bool: true when roleName names a registered system role; false otherwise.

func NewRBACWithAddress

1func NewRBACWithAddress(addr address) *RBAC
source

NewRBACWithAddress creates a new RBAC instance with addr as owner.

Parameters:

  • addr: Address stored as the initial owner of the RBAC instance.

Returns:

  • *RBAC: New RBAC manager with an empty role registry and addr as owner.

func NewRole

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

NewRole creates a new Role instance with roleName.

Parameters:

  • roleName: Role identifier stored in the new Role without normalization.
  • addr: Address stored as the role's initial assignment without validation.

Returns:

  • *Role: New role containing roleName and its initially assigned addr.

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.

Parameters:

  • caller: Address attempting to accept ownership; it must equal the recorded pending owner.

Errors:

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

Returns:

  • error: nil when ownership is transferred to caller; otherwise ErrNoPendingOwner or ErrPendingUnauthorized.

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.

Parameters:

  • caller: Address requesting the drop; it must equal the current owner.

Errors:

  • ErrUnauthorized: caller is not the current owner

Returns:

  • error: nil when owner and pending owner are cleared; otherwise ErrUnauthorized.

func IsOwner

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

IsOwner returns true if the provided caller address is the current owner.

Parameters:

  • caller: Address to compare with the stored current owner address.

Returns:

  • bool: true when caller exactly equals the current owner address; false otherwise.

func IsPendingOwner

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

IsPendingOwner returns true if the provided caller address is the pending owner.

Parameters:

  • caller: Address to compare with the stored pending owner address.

Returns:

  • bool: true when caller exactly equals the pending owner address; false otherwise.

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.

Returns:

  • address: Current owner address, or the empty address after ownership is 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.

Returns:

  • address: Pending owner address, or the empty address when 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.

Parameters:

  • newOwner: Non-zero, syntactically valid address to record as the pending owner.
  • caller: Address authorized to initiate the transfer; it must equal the current owner.

Errors:

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

Returns:

  • error: nil when the pending owner is set; otherwise ErrUnauthorized or ErrInvalidAddress.

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.

Parameters:

  • addr: Address attempting to accept ownership; it must equal the recorded pending owner.

Errors:

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

Returns:

  • error: nil when ownership is transferred to addr; otherwise ErrNoPendingOwner or ErrPendingUnauthorized.

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.

Parameters:

  • addr: Address requesting the drop; it must equal the current owner.

Errors:

  • `ErrUnauthorized`: addr is not the current owner

Returns:

  • error: nil when owner and pending owner are cleared; otherwise ErrUnauthorized.

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.

Returns:

  • map[string]address: Newly allocated map containing each registered role name and its assigned address.

func GetRoleAddress

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

GetRoleAddress returns the address assigned to roleName.

Parameters:

  • roleName: Exact role name to look up; this method does not trim whitespace.

Errors:

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

Returns:

  • address: Address assigned to roleName, or the empty address when the role is absent.
  • error: nil when roleName exists; otherwise ErrRoleDoesNotExist.

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.

Parameters:

  • roleName: Exact role name to look up in the role registry.
  • addr: Address to compare with the address assigned to roleName.

Returns:

  • bool: true when roleName exists and its assigned address equals addr; false when it does not.

func Owner

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

Owner returns the current owner address.

Returns:

  • address: Current RBAC owner address, or the empty address if ownership has been dropped.

func PendingOwner

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

PendingOwner returns the pending owner address during ownership transfer.

Returns:

  • address: Pending owner address, or the empty address when no transfer is pending.

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.

Parameters:

  • roleName: Role identifier; leading and trailing whitespace is removed before validation and storage.
  • addr: Address initially assigned to the role; this method stores it without address validation.

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.
  • A system-role name may be registered when absent, but remains protected from removal; this package does not pre-register system roles.

Returns:

  • error: nil when the trimmed role is registered; otherwise ErrInvalidRoleName or ErrRoleAlreadyExists.

func RemoveRole

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

RemoveRole removes roleName from the RBAC system.

Parameters:

  • roleName: Role identifier to remove; leading and trailing whitespace is removed before lookup.

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.)

Returns:

  • error: nil when a non-system role is removed; otherwise an error for invalid, missing, or protected roles.

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.

Parameters:

  • newOwner: Non-zero, syntactically valid address to record as the pending owner.
  • caller: Address authorized to initiate the transfer; it must equal the current owner.

Errors:

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

Returns:

  • error: nil when the pending owner is set; otherwise ErrUnauthorized or ErrInvalidAddress.

func UpdateRoleAddress

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

UpdateRoleAddress assigns addr to roleName.

Parameters:

  • roleName: Existing role identifier; leading and trailing whitespace is removed before lookup.
  • addr: Non-zero, syntactically valid address to assign to the role.

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

Returns:

  • error: nil when the existing role is updated; otherwise an error identifying invalid input or a missing role.

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.

Returns:

  • address: Address currently assigned to the role, or the empty address when unassigned.

func IsAuthorized

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

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

Parameters:

  • addr: Address to compare with the role's stored assignment.

Returns:

  • bool: true when addr exactly equals the assigned address; false otherwise.

func IsEmpty

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

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

Returns:

  • bool: true when the stored role address equals the empty address; false when an address is assigned.

func Name

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

Name returns the role's name.

Returns:

  • string: Role identifier stored in the Role.

type SystemRole

ident
1type SystemRole string
source

SystemRole represents a reserved system-role name that cannot be removed once registered.

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.

Returns:

  • string: Registered system-role name, or "Unknown" when r is not in the system-role registry.

Imports 3

  • chain stdlib
  • errors stdlib
  • strings stdlib

Source Files 8