Skip to content

Role hierarchy

Access control in XPower Banq is implemented in Acma — short for "access control management." Under the hood Acma extends OpenZeppelin's AccessManager. Every privileged function on every protocol contract is gated by a 64-bit role ID, with the mapping (target × selector → role) stored in Acma.

Three tiers per action

For each privileged action the protocol defines three related roles:

TierSuffixPower
Base…_ROLEHolders may call the gated function.
Admin…_ADMIN_ROLEHolders may grant and revoke the base role, and may modify the access-manager parameters of the base role (the time-delay, etc).
Guard…_GUARD_ROLEHolders may cancel a pending operation scheduled against the base role.

The base role is what gets things done; the admin is what changes who can do them; the guard is the circuit breaker that can veto a pending change before its delay elapses. This is the AccessManager model — XPower Banq does not invent its own ACL.

The base verbs

Across all the protocol contracts the base actions reduce to a small set of verbs (defined in the Roles library):

VerbWhere it gatesWhat the holder can do
SET_TARGETPosition / Vault / Pool / FeedSchedule a new value for a parameter target
TMP_TARGETPosition / Vault / Pool / FeedApply a temporary parameter override
CAP_SUPPLYPoolSet per-token supply cap
TMP_SUPPLYPoolApply a temporary supply cap override
CAP_BORROWPoolSet per-token borrow cap
TMP_BORROWPoolApply a temporary borrow cap override
ENLISTPool / FeedAdd a supported token (Pool) or a price source (Feed)
ENWRAPPoolMint a wrapped position
RETWAPFeedRefresh the TWAP price
SQUAREPoolLiquidate (the keeper-callable internal entrypoint behind liquidate)
RELATEAcmaWire a new (target, selector) into a role

Combined with the host component prefix (SUPPLY_…, BORROW_…, VAULT_…, FEED_…, POOL_…, ACMA_…) you get the concrete roles named in Acma: POOL_SQUARE_ROLE, FEED_RETWAP_ROLE, POOL_CAP_SUPPLY_ROLE, SUPPLY_SET_TARGET_ROLE, and so on. Each one has matching …_ADMIN_ROLE and …_GUARD_ROLE companions.

How "lethargic" enters the picture

The AccessManager lets a role's admin set a per-target execution delay. When a parameter change is scheduled through a delayed role:

  1. The admin schedules the call. The change is not effective yet.
  2. A timer counts down for the configured delay.
  3. During the wait, a guard may call cancel(...) to abort.
  4. When the timer elapses, anyone can execute(...) to apply the scheduled call. The supervisor on the target contract then enforces its own per-cycle multiplicative bound and absolute range before accepting the new value.

So "lethargic governance" is the composition of three things: (1) the access-manager delay between scheduling and executing, (2) the guard's ability to cancel during that delay, and (3) the supervisor's per-cycle ≤ 2× / ≥ 0.5× bound. Each layer is enforced by code; none can be skipped by the admin.

What the guard can and cannot do

A guard cannot propose changes — only block scheduled ones. It is a circuit-breaker, not a co-author. If a change makes it through both the admin's schedule and the delay window, it lands; the guard's window has closed.

Beyond parameters

The same role machinery covers non-parameter operations:

  • Adding tokens to a pool — POOL_ENLIST_ROLE
  • Wrapping a positionPOOL_ENWRAP_ROLE
  • Refreshing oraclesFEED_RETWAP_ROLE
  • Adjusting the role-to-selector map itselfACMA_RELATE_ROLE
  • Permissionless pathsliquidate, retwap, supply, borrow etc. additionally support a PoW-gated public mode that bypasses the role check at the cost of compute (see PoW-gated public mode)

Where to go next