Complete role-based access control reference for Stablecoin OFT and ERC20Plus. All roles use AccessControl2StepUpgradeable with two-step admin transfer and keccak256 identifiers.
Stablecoin OFT
Applies to OFTBurnMint, OFTBurnSelfMint, OFTLockUnlock, OFTNative, and the alt variants of OFTBurnMint, OFTBurnSelfMint, and OFTLockUnlock.
| Role | Source | Used For |
|---|
DEFAULT_ADMIN_ROLE | AccessControl2StepUpgradeable | setPeer, setEnforcedOptions, setMsgInspector, setFeeDeposit, delegate operations |
FEE_CONFIG_MANAGER_ROLE | FeeConfigRBACUpgradeable | setDefaultFeeBps, setFeeBps |
RATE_LIMITER_MANAGER_ROLE | RateLimiterRBACUpgradeable | setRateLimitGlobalConfig, setRateLimitConfigs, setRateLimitStates, setRateLimitAddressExemptions, checkpointRateLimits |
PAUSER_ROLE | PauseByIDRBACUpgradeable | setDefaultPaused (when pausing), setPaused (when effectively pausing) |
UNPAUSER_ROLE | PauseByIDRBACUpgradeable | setDefaultPaused (when unpausing), setPaused (when effectively unpausing or no-op) |
DEFAULT_ADMIN_ROLE is synchronized with delegate. The setDelegate function always reverts.
ERC20Plus
| Role | Source | Used For |
|---|
DEFAULT_ADMIN_ROLE | AccessControl2StepUpgradeable | Admin transfer, set allowlist mode, recoverFunds |
MINTER_ROLE | Declared locally | mint |
BURNER_ROLE | Declared locally | burn |
BLACKLISTER_ROLE | AllowlistRBACUpgradeable | Blacklist addresses |
WHITELISTER_ROLE | AllowlistRBACUpgradeable | Whitelist addresses |
PAUSER_ROLE | PauseRBACUpgradeable | Pause |
UNPAUSER_ROLE | PauseRBACUpgradeable | Unpause |
Role-to-Function Matrix
ERC20Plus Functions
| Function | Required Role |
|---|
mint(address, uint256) | MINTER_ROLE |
burn(address, uint256) | BURNER_ROLE |
recoverFunds(address, address, uint256) | DEFAULT_ADMIN_ROLE |
setAllowlistMode(AllowlistMode) | DEFAULT_ADMIN_ROLE |
setBlacklisted(SetAllowlistParam[]) | BLACKLISTER_ROLE |
setWhitelisted(SetAllowlistParam[]) | WHITELISTER_ROLE |
pause() | PAUSER_ROLE |
unpause() | UNPAUSER_ROLE |
OFT Functions
| Function | Required Role |
|---|
setDefaultFeeBps(uint16) | FEE_CONFIG_MANAGER_ROLE |
setFeeBps(uint256, uint16, bool) | FEE_CONFIG_MANAGER_ROLE |
setRateLimitGlobalConfig(RateLimitGlobalConfig) | RATE_LIMITER_MANAGER_ROLE |
setRateLimitConfigs(SetRateLimitConfigParam[]) | RATE_LIMITER_MANAGER_ROLE |
setRateLimitStates(SetRateLimitStateParam[]) | RATE_LIMITER_MANAGER_ROLE |
setRateLimitAddressExemptions(SetRateLimitAddressExceptionParam[]) | RATE_LIMITER_MANAGER_ROLE |
checkpointRateLimits(uint256[]) | RATE_LIMITER_MANAGER_ROLE |
setDefaultPaused(bool) | PAUSER_ROLE or UNPAUSER_ROLE |
setPaused(SetPausedParam[]) | PAUSER_ROLE or UNPAUSER_ROLE |
setPeer(uint32, bytes32) | DEFAULT_ADMIN_ROLE |
setEnforcedOptions(EnforcedOptionParam[]) | DEFAULT_ADMIN_ROLE |
setMsgInspector(address) | DEFAULT_ADMIN_ROLE |
setFeeDeposit(address) | DEFAULT_ADMIN_ROLE |
Permissionless Functions
These functions can be called by anyone:
| Function | Contract |
|---|
send(SendParam, MessagingFee, address) | OFTs |
quoteSend(SendParam, bool) | OFTs |
quoteOFT(SendParam) | OFTs |
token() | OFTs |
approvalRequired() | OFTs |
oftVersion() | OFTs |
sharedDecimals() | OFTs |
transfer(address, uint256) | ERC20Plus (subject to allowlist + pause) |
transferFrom(address, address, uint256) | ERC20Plus (subject to allowlist + pause) |
approve(address, uint256) | ERC20Plus |
permit(...) | ERC20Plus |
defaultFeeBps() | OFTs |
feeBps(uint256) | OFTs |
getRateLimitGlobalConfig() | OFTs |
rateLimits(uint256) | OFTs |
getRateLimitUsages(uint256) | OFTs |
isRateLimitAddressExempt(address) | OFTs |
isPaused(uint256) | OFTs |
defaultPaused() | OFTs |
pauseConfig(uint256) | OFTs |
allowlistMode() | ERC20Plus |
isAllowlisted(address) | ERC20Plus |
isBlacklisted(address) | ERC20Plus |
isWhitelisted(address) | ERC20Plus |
blacklistedCount() | ERC20Plus |
whitelistedCount() | ERC20Plus |
getBlacklist(uint256, uint256) | ERC20Plus |
getWhitelist(uint256, uint256) | ERC20Plus |
Role Separation Principles
Pauser / Unpauser — A compromised pauser key can halt the system (disruptive, but funds remain safe). If that same key could also unpause, an attacker could undo a legitimate security pause. Keeping them separate means the security team can pause fast, and unpausing requires a different authorization path (typically a governance multisig).
Fee config manager — A compromised FEE_CONFIG_MANAGER_ROLE can set high fee rates, but fee proceeds are pushed to the fee deposit address during _debit as part of the send path; the fee config manager cannot retarget that destination. Use a multisig for fee administration and monitor DefaultFeeBpsSet / FeeBpsSet events.
Minter / Burner — Different risk profiles. A compromised minter inflates supply; a compromised burner destroys user funds. In practice, both roles should only be granted to OFT contracts, never to EOAs.
Blacklister / Whitelister — Different compliance functions and different teams. Blacklisting is reactive (sanctions, fraud), typically handled by compliance or security. Whitelisting is proactive (KYC onboarding), typically handled by an onboarding team. Separating them matches the org chart.
Next Steps