# RBAC
Role-based access control management realm.
## Overview
RBAC realm manages role addresses and permissions for the GnoSwap protocol, integrating with the access package.
## Configuration
- **Admin/Governance Control**: Role management by admin or governance
- **Dynamic Roles**: Add/remove at runtime
- **Access Integration**: Syncs with access package
- **Owner-Managed Admin Role**: `admin` role is bound to RBAC owner and cannot be updated via `UpdateRoleAddress`
## Key Functions
### `RegisterRole(cur realm, roleName string, roleAddress address)`
Registers new role in system. Only callable by admin or governance.
### `RemoveRole(cur realm, roleName string)`
Removes existing role. Only callable by admin or governance. System roles cannot be removed.
### `UpdateRoleAddress(cur realm, roleName string, addr address)`
Updates address for role. Only callable by admin or governance.
The `admin` role is not updatable via this function and is managed through ownership transfer.
### `GetRoleAddress(roleName string) (address, error)`
Returns address for role.
### `IsOwner(addr address) bool`
Returns true if addr is the current owner.
### `IsPendingOwner(addr address) bool`
Returns true if addr is the pending owner.
### `GetOwner() address`
Returns the current owner address.
### `GetPendingOwner() address`
Returns the pending owner address.
### `TransferOwnership(cur realm, newOwner address)`
Initiates two-step ownership transfer. Only callable by current owner.
### `AcceptOwnership(cur realm)`
Accepts pending ownership transfer. Only callable by pending owner.
Also updates the `admin` role address and syncs it to the access package.
## Gnoweb
`Render("")` shows the owner, pending owner (`None` when absent), and the fixed
system-role assignments. Unassigned roles are explicit; custom roles are not
enumerated. Unsupported paths return `404`.
## Usage
```go
// Register new role (requires admin or governance)
RegisterRole(cross(cur), "new_role", roleAddress)
// Update role address
UpdateRoleAddress(cross(cur), "staker", newAddress)
// Admin role is updated via ownership transfer
TransferOwnership(cross(cur), newAdmin)
AcceptOwnership(cross(cur))
// Get role address
addr, err := GetRoleAddress("router")
// Transfer ownership (two-step)
TransferOwnership(cross(cur), newAdmin) // Step 1: Initiate
AcceptOwnership(cross(cur)) // Step 2: Accept (by newAdmin)
```
## Contract Upgrade
RBAC supports contract upgrades by changing role addresses. Versioned implementations live under component-specific realm paths (for example, `gno.land/r/gnoswap/pool/v1`), while the stable realm resolves calls through the current role address.
### Upgrade Process
1. **Deploy a new component version** under its versioned realm path.
2. **Update the relevant role address** to point to the new implementation.
3. **Verify distribution and call flows** use the new role address.
### Versioned Components
This checkout contains versioned implementations for:
- `pool`
- `position`
- `router`
- `staker`
- `gov/governance`
- `gov/staker`
- `launchpad`
- `protocol_fee`
The `community_pool` role is a distribution and treasury destination, not a versioned component. Updating that role redirects distributions to the selected address.
### Example: GNS Distribution Upgrade
```go
func changeDistributionTarget(cur realm) {
// Update role addresses through the RBAC realm.
rbac.UpdateRoleAddress(cross(cur), "staker", newStakerAddr)
rbac.UpdateRoleAddress(cross(cur), "gov_staker", newGovStakerAddr)
rbac.UpdateRoleAddress(cross(cur), "devops", newDevOpsAddr)
// community_pool is a distribution target, not a versioned implementation.
rbac.UpdateRoleAddress(cross(cur), "community_pool", newCommunityPoolAddr)
}
```
### Test Example
The upgrade mechanism is demonstrated in the [upgrade scenario test](../../../scenario/upgrade/change_gns_distribution_target_filetest.gno).
```go
// The scenario initializes distribution targets, updates role addresses,
// and verifies that subsequent GNS distributions use the new addresses.
func changeDistributionTarget(cur realm) {
rbac.UpdateRoleAddress(cross(cur), "staker", newStakerAddr)
rbac.UpdateRoleAddress(cross(cur), "gov_staker", newGovStakerAddr)
rbac.UpdateRoleAddress(cross(cur), "devops", newDevOpsAddr)
rbac.UpdateRoleAddress(cross(cur), "community_pool", newCommunityPoolAddr)
}
```
## Security
- Admin or governance authorization is required for role management
- Ownership transfer is restricted to the current owner and pending owner
- Role updates are synchronized with the access package
- Role validation is performed before updates
AcceptOwnership(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})
GetOwner() string
GetPendingOwner() string
GetRoleAddress(roleName string) (string, interface {Error func() string})
IsOwner(addr string) bool
IsPendingOwner(addr string) bool
RegisterRole(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, roleName string, roleAddress string)
RemoveRole(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, roleName string)
Render(path string) string
TransferOwnership(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string)
UpdateRoleAddress(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, roleName string, addr string)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.