Skip to main content

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.

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:
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");
Reserve Folio uses OpenZeppelin’s AccessControlEnumerable for role management, allowing enumeration of all role members.

Core Roles

DEFAULT_ADMIN_ROLE

The primary owner and administrator of the Folio.

DEFAULT_ADMIN_ROLE

Expected Holder: Timelock of Slow Folio GovernorPermissions:
  • 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

Key Functions

// Add token to basket
function addToBasket(IERC20 token) external onlyRole(DEFAULT_ADMIN_ROLE)

// Remove token from basket (with restrictions)
function removeFromBasket(IERC20 token) external
DEFAULT_ADMIN_ROLE has extensive control. It should ALWAYS be held by a timelock with significant delay (7-14 days).

REBALANCE_MANAGER

Controls the rebalancing process and auction lifecycle.

REBALANCE_MANAGER

Expected Holder: Timelock of Fast Folio GovernorPermissions:
  • Start rebalances with target parameters
  • End rebalances early
  • Close individual auctions

Key Functions

// 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

  • Define token inclusion and weights
  • Set conservative price ranges
  • Configure basket limits (BU/share targets)
  • Set auction launcher window duration
  • Set rebalance TTL
  • Monitor ongoing rebalances
  • End rebalances if market conditions change dramatically
  • Coordinate with AUCTION_LAUNCHER on execution
  • Ensure price ranges remain appropriate
REBALANCE_MANAGER typically has a shorter timelock than DEFAULT_ADMIN_ROLE (1-3 days) to enable responsive rebalancing.

AUCTION_LAUNCHER

Provides precision and responsiveness during rebalancing.

AUCTION_LAUNCHER

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

Key Functions

// 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

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)

Price Control Impact

No Price ControlAUCTION_LAUNCHER cannot modify prices from governance-set ranges.
RebalanceControl({
    weightControl: false,
    priceControl: PriceControl.NONE
})
  • Most restrictive
  • Auction length must be maxAuctionLength
  • Safest for untrusted AUCTION_LAUNCHER

Revocation

If AUCTION_LAUNCHER behaves maliciously:
// 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.

BRAND_MANAGER

Expected Holder: Marketing/Brand team (optional)Permissions: NONE (on-chain)Purpose: Off-chain identification of brand managers for marketing, social media, and community management.
BRAND_MANAGER has no on-chain permissions. It exists purely for off-chain tooling and identification purposes.

Role Management

Roles are managed using OpenZeppelin’s AccessControl:

Granting Roles

// 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

// Only DEFAULT_ADMIN_ROLE can revoke roles
function revokeRole(bytes32 role, address account) external

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

Renouncing Roles

// 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

// 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)
// 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);
}

Typical Role Configuration

A well-configured Folio typically has:
1

DEFAULT_ADMIN_ROLE

Holder: Slow Governor’s Timelock (7-14 day delay)Purpose: Critical parameter changes and emergency actions
folio.grantRole(DEFAULT_ADMIN_ROLE, slowTimelockAddress);
2

REBALANCE_MANAGER

Holder: Fast Governor’s Timelock (1-3 day delay)Purpose: Start and manage rebalances
folio.grantRole(REBALANCE_MANAGER, fastTimelockAddress);
3

AUCTION_LAUNCHER

Holder: Trusted EOA or Multisig (no timelock)Purpose: Responsive auction execution
folio.grantRole(AUCTION_LAUNCHER, multisigAddress);
4

BRAND_MANAGER

Holder: Brand/Marketing team (optional)Purpose: Off-chain identification
folio.grantRole(BRAND_MANAGER, brandTeamAddress);

Multi-Holder Roles

Roles can have multiple holders:
// 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);
Multiple DEFAULT_ADMIN_ROLE holders reduce security. Only add additional admins for emergency recovery purposes.

Role Transition

Transitioning roles should be done carefully:
1

Grant New Role

folio.grantRole(AUCTION_LAUNCHER, newMultisig);
2

Test New Holder

Verify the new role holder can perform their duties before removing the old one.
3

Revoke Old Role

folio.revokeRole(AUCTION_LAUNCHER, oldMultisig);

Emergency Scenarios

Compromised AUCTION_LAUNCHER

1

Immediate Revocation

// Via DEFAULT_ADMIN_ROLE
folio.revokeRole(AUCTION_LAUNCHER, compromisedAddress);
2

End Active Rebalance

// If rebalance is ongoing and could leak value
folio.endRebalance();
3

Grant New Role

folio.grantRole(AUCTION_LAUNCHER, newTrustedAddress);

Lost AUCTION_LAUNCHER Access

If AUCTION_LAUNCHER goes offline:
No immediate action needed. After the restricted period expires, auctions can be opened permissionlessly via openAuctionUnrestricted().
// Anyone can call after restricted period
folio.openAuctionUnrestricted(rebalanceNonce);

Lost DEFAULT_ADMIN_ROLE Access

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

Best Practices

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
  • Longer delays for higher privilege roles
  • Balance security with responsiveness
  • Document timelock parameters
  • Test timelock execution before mainnet
  • Monitor all role-gated function calls
  • Set up alerts for privilege escalation
  • Review role membership periodically
  • Have revocation procedures ready
  • Document emergency response plans
  • Document role holders publicly
  • Explain role responsibilities
  • Maintain contact information
  • Update documentation when roles change
  • Be transparent about role holder identities

Role Verification

Verify role configuration before mainnet deployment:
// 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));
}

Build docs developers (and LLMs) love