> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/reserve-protocol/reserve-index-dtf/llms.txt
> Use this file to discover all available pages before exploring further.

# Role System

> Understand the role-based access control system in Reserve Folio

## Overview

Reserve Folio uses a role-based access control (RBAC) system to separate concerns and enable secure, flexible governance. Each role has specific permissions designed to balance security with operational flexibility.

## Role Constants

Roles are defined as `bytes32` constants:

```solidity theme={null}
bytes32 constant DEFAULT_ADMIN_ROLE = 0x00;
bytes32 constant REBALANCE_MANAGER = keccak256("REBALANCE_MANAGER");
bytes32 constant AUCTION_LAUNCHER = keccak256("AUCTION_LAUNCHER");
bytes32 constant BRAND_MANAGER = keccak256("BRAND_MANAGER");
```

<Info>
  Reserve Folio uses OpenZeppelin's `AccessControlEnumerable` for role management, allowing enumeration of all role members.
</Info>

## Core Roles

### DEFAULT\_ADMIN\_ROLE

The primary owner and administrator of the Folio.

<Card title="DEFAULT_ADMIN_ROLE" icon="crown">
  **Expected Holder:** Timelock of Slow Folio Governor

  **Permissions:**

  * Add/remove basket assets
  * Set fees (TVL, mint, folio self fee)
  * Configure fee recipients
  * Set auction parameters (max auction length)
  * Configure other roles (grant/revoke)
  * Set mandate (mission statement)
  * Set Folio name
  * Configure trusted filler registry
  * Set rebalance control parameters
  * Enable/disable permissionless bids
  * Configure trade allowlist
  * Deprecate the Folio
  * Close auctions and rebalances
</Card>

#### Key Functions

<Tabs>
  <Tab title="Asset Management">
    ```solidity theme={null}
    // Add token to basket
    function addToBasket(IERC20 token) external onlyRole(DEFAULT_ADMIN_ROLE)

    // Remove token from basket (with restrictions)
    function removeFromBasket(IERC20 token) external
    ```
  </Tab>

  <Tab title="Fee Configuration">
    ```solidity theme={null}
    // Set TVL fee (annual percentage)
    function setTVLFee(uint256 _newFee) external onlyRole(DEFAULT_ADMIN_ROLE)

    // Set mint fee (percentage)
    function setMintFee(uint256 _newFee) external onlyRole(DEFAULT_ADMIN_ROLE)

    // Set folio self fee (burn fraction)
    function setFolioSelfFee(uint256 _newFee) external onlyRole(DEFAULT_ADMIN_ROLE)

    // Configure fee recipients
    function setFeeRecipients(
        FeeRecipient[] calldata _newRecipients
    ) external onlyRole(DEFAULT_ADMIN_ROLE)
    ```
  </Tab>

  <Tab title="System Configuration">
    ```solidity theme={null}
    // Set maximum auction length
    function setMaxAuctionLength(uint256 _newLength) 
        external onlyRole(DEFAULT_ADMIN_ROLE)

    // Set mandate
    function setMandate(string calldata _newMandate) 
        external onlyRole(DEFAULT_ADMIN_ROLE)

    // Set Folio name
    function setName(string calldata _newName) 
        external onlyRole(DEFAULT_ADMIN_ROLE)

    // Configure trusted filler registry
    function setTrustedFillerRegistry(address _newFillerRegistry, bool _enabled) 
        external onlyRole(DEFAULT_ADMIN_ROLE)

    // Set rebalance control
    function setRebalanceControl(RebalanceControl calldata _rebalanceControl) 
        external onlyRole(DEFAULT_ADMIN_ROLE)

    // Enable/disable permissionless bids
    function setBidsEnabled(bool _bidsEnabled) 
        external onlyRole(DEFAULT_ADMIN_ROLE)
    ```
  </Tab>

  <Tab title="Emergency Actions">
    ```solidity theme={null}
    // Deprecate the Folio (redemption-only mode)
    function deprecateFolio() external onlyRole(DEFAULT_ADMIN_ROLE)

    // Close an auction
    function closeAuction(uint256 auctionId) external

    // End a rebalance
    function endRebalance() external
    ```
  </Tab>
</Tabs>

<Warning>
  DEFAULT\_ADMIN\_ROLE has extensive control. It should ALWAYS be held by a timelock with significant delay (7-14 days).
</Warning>

### REBALANCE\_MANAGER

Controls the rebalancing process and auction lifecycle.

<Card title="REBALANCE_MANAGER" icon="shuffle">
  **Expected Holder:** Timelock of Fast Folio Governor

  **Permissions:**

  * Start rebalances with target parameters
  * End rebalances early
  * Close individual auctions
</Card>

#### Key Functions

```solidity theme={null}
// Start a new rebalance
function startRebalance(
    TokenRebalanceParams[] calldata tokens,
    RebalanceLimits calldata limits,
    uint256 auctionLauncherWindow,
    uint256 ttl
) external onlyRole(REBALANCE_MANAGER)

// End the current rebalance
function endRebalance() external // REBALANCE_MANAGER or ADMIN or AUCTION_LAUNCHER

// Close an auction
function closeAuction(uint256 auctionId) external // REBALANCE_MANAGER or ADMIN or AUCTION_LAUNCHER
```

#### Responsibilities

<AccordionGroup>
  <Accordion title="Setting Rebalance Targets">
    * Define token inclusion and weights
    * Set conservative price ranges
    * Configure basket limits (BU/share targets)
    * Set auction launcher window duration
    * Set rebalance TTL
  </Accordion>

  <Accordion title="Risk Management">
    * Monitor ongoing rebalances
    * End rebalances if market conditions change dramatically
    * Coordinate with AUCTION\_LAUNCHER on execution
    * Ensure price ranges remain appropriate
  </Accordion>
</AccordionGroup>

<Info>
  REBALANCE\_MANAGER typically has a shorter timelock than DEFAULT\_ADMIN\_ROLE (1-3 days) to enable responsive rebalancing.
</Info>

### AUCTION\_LAUNCHER

Provides precision and responsiveness during rebalancing.

<Card title="AUCTION_LAUNCHER" icon="rocket">
  **Expected Holder:** EOA or Multisig (semi-trusted)

  **Permissions:**

  * Open auctions during restricted period
  * Select subset of tokens for each auction
  * Adjust basket weight ranges (if weightControl enabled)
  * Adjust price ranges (if priceControl != NONE)
  * Adjust basket limits (within governance range)
  * Set individual auction lengths
  * End auctions and rebalances
</Card>

#### Key Functions

```solidity theme={null}
// Open an auction with specific parameters
function openAuction(
    uint256 rebalanceNonce,
    address[] calldata tokens,
    WeightRange[] calldata newWeights,
    PriceRange[] calldata newPrices,
    RebalanceLimits calldata newLimits,
    uint256 auctionLength
) external onlyRole(AUCTION_LAUNCHER) returns (uint256 auctionId)

// Close an auction
function closeAuction(uint256 auctionId) external

// End a rebalance
function endRebalance() external
```

#### Trust Assumptions

<Warning>
  The AUCTION\_LAUNCHER is **semi-trusted** and can act maliciously within bounds:

  **Should Do:**

  * Open auctions promptly during restricted period
  * Progressively narrow BU limits to DCA responsibly
  * End rebalances when prices move outside ranges
  * Provide accurate price ranges within governance bounds
  * If weightControl: Maintain original rebalance intent
  * If priceControl=PARTIAL: Provide ranges including current clearing price
  * If priceControl=ATOMIC\_SWAP: Fill atomically and end rebalance immediately

  **Should NOT Do:**

  * Close auctions/rebalances dishonestly to deny rebalancing
  * Set prices to leak value (especially with ATOMIC\_SWAP)
  * Deviate from governance intent
  * Go offline indefinitely (auctions can proceed permissionlessly)
</Warning>

#### Price Control Impact

<Tabs>
  <Tab title="NONE">
    **No Price Control**

    AUCTION\_LAUNCHER cannot modify prices from governance-set ranges.

    ```solidity theme={null}
    RebalanceControl({
        weightControl: false,
        priceControl: PriceControl.NONE
    })
    ```

    * Most restrictive
    * Auction length must be `maxAuctionLength`
    * Safest for untrusted AUCTION\_LAUNCHER
  </Tab>

  <Tab title="PARTIAL">
    **Partial Price Control**

    AUCTION\_LAUNCHER can narrow price ranges within initial bounds.

    ```solidity theme={null}
    RebalanceControl({
        weightControl: true,
        priceControl: PriceControl.PARTIAL
    })
    ```

    * Can improve execution quality
    * Risk: Can leak value via dishonest prices
    * Cannot guarantee being the beneficiary
    * Requires moderate trust
  </Tab>

  <Tab title="ATOMIC_SWAP">
    **Full Price Control**

    AUCTION\_LAUNCHER can perform atomic swaps at fixed prices.

    ```solidity theme={null}
    RebalanceControl({
        weightControl: true,
        priceControl: PriceControl.ATOMIC_SWAP
    })
    ```

    * Can set `startPrice == endPrice`
    * Bypasses warmup period
    * Risk: Can leak value AND be the beneficiary
    * Requires high trust
    * Should end rebalance immediately after swap
  </Tab>
</Tabs>

#### Revocation

If AUCTION\_LAUNCHER behaves maliciously:

```solidity theme={null}
// DEFAULT_ADMIN_ROLE revokes the role
folio.revokeRole(AUCTION_LAUNCHER, maliciousAddress);

// Auctions can now proceed permissionlessly after restricted period
```

### BRAND\_MANAGER

An optional, permissionless role for off-chain use.

<Card title="BRAND_MANAGER" icon="palette">
  **Expected Holder:** Marketing/Brand team (optional)

  **Permissions:** NONE (on-chain)

  **Purpose:** Off-chain identification of brand managers for marketing, social media, and community management.
</Card>

<Info>
  BRAND\_MANAGER has no on-chain permissions. It exists purely for off-chain tooling and identification purposes.
</Info>

## Role Management

Roles are managed using OpenZeppelin's AccessControl:

### Granting Roles

```solidity theme={null}
// Only DEFAULT_ADMIN_ROLE can grant roles
function grantRole(bytes32 role, address account) external

// Example
folio.grantRole(REBALANCE_MANAGER, timelockAddress);
folio.grantRole(AUCTION_LAUNCHER, multisigAddress);
```

### Revoking Roles

```solidity theme={null}
// Only DEFAULT_ADMIN_ROLE can revoke roles
function revokeRole(bytes32 role, address account) external

// Example
folio.revokeRole(AUCTION_LAUNCHER, oldMultisig);
```

### Renouncing Roles

```solidity theme={null}
// Any role holder can renounce their own role
function renounceRole(bytes32 role, address account) external

// Example (called by the role holder)
folio.renounceRole(AUCTION_LAUNCHER, msg.sender);
```

### Querying Roles

```solidity theme={null}
// Check if an address has a role
function hasRole(bytes32 role, address account) external view returns (bool)

// Get number of role members
function getRoleMemberCount(bytes32 role) external view returns (uint256)

// Get role member by index
function getRoleMember(bytes32 role, uint256 index) external view returns (address)
```

<CodeGroup>
  ```solidity Example: Check Roles theme={null}
  // Check if address has REBALANCE_MANAGER
  if (folio.hasRole(REBALANCE_MANAGER, address(timelock))) {
      // Timelock can start rebalances
  }

  // List all AUCTION_LAUNCHER role holders
  uint256 count = folio.getRoleMemberCount(AUCTION_LAUNCHER);
  for (uint256 i = 0; i < count; i++) {
      address launcher = folio.getRoleMember(AUCTION_LAUNCHER, i);
      console.log("Auction Launcher:", launcher);
  }
  ```
</CodeGroup>

## Typical Role Configuration

A well-configured Folio typically has:

<Steps>
  <Step title="DEFAULT_ADMIN_ROLE">
    **Holder:** Slow Governor's Timelock (7-14 day delay)

    **Purpose:** Critical parameter changes and emergency actions

    ```solidity theme={null}
    folio.grantRole(DEFAULT_ADMIN_ROLE, slowTimelockAddress);
    ```
  </Step>

  <Step title="REBALANCE_MANAGER">
    **Holder:** Fast Governor's Timelock (1-3 day delay)

    **Purpose:** Start and manage rebalances

    ```solidity theme={null}
    folio.grantRole(REBALANCE_MANAGER, fastTimelockAddress);
    ```
  </Step>

  <Step title="AUCTION_LAUNCHER">
    **Holder:** Trusted EOA or Multisig (no timelock)

    **Purpose:** Responsive auction execution

    ```solidity theme={null}
    folio.grantRole(AUCTION_LAUNCHER, multisigAddress);
    ```
  </Step>

  <Step title="BRAND_MANAGER">
    **Holder:** Brand/Marketing team (optional)

    **Purpose:** Off-chain identification

    ```solidity theme={null}
    folio.grantRole(BRAND_MANAGER, brandTeamAddress);
    ```
  </Step>
</Steps>

## Multi-Holder Roles

Roles can have multiple holders:

```solidity theme={null}
// Multiple AUCTION_LAUNCHERs
folio.grantRole(AUCTION_LAUNCHER, primaryMultisig);
folio.grantRole(AUCTION_LAUNCHER, backupMultisig);

// Multiple admins (generally not recommended)
folio.grantRole(DEFAULT_ADMIN_ROLE, slowTimelock);
folio.grantRole(DEFAULT_ADMIN_ROLE, emergencyTimelock);
```

<Warning>
  Multiple DEFAULT\_ADMIN\_ROLE holders reduce security. Only add additional admins for emergency recovery purposes.
</Warning>

## Role Transition

Transitioning roles should be done carefully:

<Steps>
  <Step title="Grant New Role">
    ```solidity theme={null}
    folio.grantRole(AUCTION_LAUNCHER, newMultisig);
    ```
  </Step>

  <Step title="Test New Holder">
    Verify the new role holder can perform their duties before removing the old one.
  </Step>

  <Step title="Revoke Old Role">
    ```solidity theme={null}
    folio.revokeRole(AUCTION_LAUNCHER, oldMultisig);
    ```
  </Step>
</Steps>

## Emergency Scenarios

### Compromised AUCTION\_LAUNCHER

<Steps>
  <Step title="Immediate Revocation">
    ```solidity theme={null}
    // Via DEFAULT_ADMIN_ROLE
    folio.revokeRole(AUCTION_LAUNCHER, compromisedAddress);
    ```
  </Step>

  <Step title="End Active Rebalance">
    ```solidity theme={null}
    // If rebalance is ongoing and could leak value
    folio.endRebalance();
    ```
  </Step>

  <Step title="Grant New Role">
    ```solidity theme={null}
    folio.grantRole(AUCTION_LAUNCHER, newTrustedAddress);
    ```
  </Step>
</Steps>

### Lost AUCTION\_LAUNCHER Access

If AUCTION\_LAUNCHER goes offline:

<Info>
  **No immediate action needed.** After the restricted period expires, auctions can be opened permissionlessly via `openAuctionUnrestricted()`.
</Info>

```solidity theme={null}
// Anyone can call after restricted period
folio.openAuctionUnrestricted(rebalanceNonce);
```

### Lost DEFAULT\_ADMIN\_ROLE Access

<Warning>
  **Critical scenario.** If DEFAULT\_ADMIN\_ROLE access is lost and no backup exists:

  * Cannot change fees
  * Cannot add/remove assets
  * Cannot configure other roles
  * Cannot upgrade (if upgradeable)

  **Prevention:**

  * Always use a timelock controlled by governance
  * Consider a backup timelock with longer delays
  * Document recovery procedures
</Warning>

## Best Practices

<AccordionGroup>
  <Accordion title="Role Holder Selection">
    **DEFAULT\_ADMIN\_ROLE:**

    * MUST be a timelock (7-14 days)
    * Controlled by slow, careful governance
    * Multiple signers if using multisig governance

    **REBALANCE\_MANAGER:**

    * SHOULD be a timelock (1-3 days)
    * Controlled by faster governance
    * Same voting token as DEFAULT\_ADMIN\_ROLE

    **AUCTION\_LAUNCHER:**

    * CAN be EOA or multisig
    * Should be trusted but replace if malicious
    * Consider multisig with 2-of-3 or 3-of-5
  </Accordion>

  <Accordion title="Timelock Configuration">
    * Longer delays for higher privilege roles
    * Balance security with responsiveness
    * Document timelock parameters
    * Test timelock execution before mainnet
  </Accordion>

  <Accordion title="Monitoring and Response">
    * Monitor all role-gated function calls
    * Set up alerts for privilege escalation
    * Review role membership periodically
    * Have revocation procedures ready
    * Document emergency response plans
  </Accordion>

  <Accordion title="Documentation">
    * Document role holders publicly
    * Explain role responsibilities
    * Maintain contact information
    * Update documentation when roles change
    * Be transparent about role holder identities
  </Accordion>
</AccordionGroup>

## Role Verification

Verify role configuration before mainnet deployment:

<CodeGroup>
  ```solidity Verification Script theme={null}
  // Check all role assignments
  console.log("=== Role Configuration ===");

  // DEFAULT_ADMIN_ROLE
  uint256 adminCount = folio.getRoleMemberCount(DEFAULT_ADMIN_ROLE);
  console.log("DEFAULT_ADMIN_ROLE count:", adminCount);
  for (uint256 i = 0; i < adminCount; i++) {
      console.log("  -", folio.getRoleMember(DEFAULT_ADMIN_ROLE, i));
  }

  // REBALANCE_MANAGER
  uint256 rebalanceCount = folio.getRoleMemberCount(REBALANCE_MANAGER);
  console.log("REBALANCE_MANAGER count:", rebalanceCount);
  for (uint256 i = 0; i < rebalanceCount; i++) {
      console.log("  -", folio.getRoleMember(REBALANCE_MANAGER, i));
  }

  // AUCTION_LAUNCHER
  uint256 launcherCount = folio.getRoleMemberCount(AUCTION_LAUNCHER);
  console.log("AUCTION_LAUNCHER count:", launcherCount);
  for (uint256 i = 0; i < launcherCount; i++) {
      console.log("  -", folio.getRoleMember(AUCTION_LAUNCHER, i));
  }
  ```
</CodeGroup>
