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

Folio Protocol supports sophisticated governance structures with:
  • Role-based access control for different operations
  • On-chain governance with voting and timelocks
  • Dual governance (owner governance + trading governance)
  • Vote delegation and staking mechanisms
Folios can be governed by multisigs, DAOs, or fully on-chain governance contracts. You can also mix approaches for different roles.

Governance Roles

Folios use three primary roles:

DEFAULT_ADMIN_ROLE

  • Set fees and fee recipients
  • Configure auction parameters
  • Add/remove basket assets
  • Deprecate the Folio
  • Manage role assignments

REBALANCE_MANAGER

  • Start new rebalances
  • End ongoing rebalances
  • Close individual auctions

AUCTION_LAUNCHER

  • Open restricted auctions
  • Narrow price/weight ranges
  • Control auction timing
  • Close auctions
There’s also a BRAND_MANAGER role for off-chain use (no on-chain permissions).

Deployment Options

Option 1: Manual Role Assignment

Deploy a raw Folio and assign roles directly:
// Deploy Folio
(Folio folio, address proxyAdmin) = folioDeployer.deployFolio(
    basicDetails,
    additionalDetails,
    flags,
    multisigAddress,           // DEFAULT_ADMIN_ROLE
    [tradingMultisig],         // REBALANCE_MANAGER
    [auctionBotEOA],           // AUCTION_LAUNCHER
    [],                        // BRAND_MANAGER
    deploymentNonce
);

// Roles are assigned during deployment
Use cases:
  • Multisig-controlled Folios
  • Testing and development
  • Simple governance structures
  • EOA-operated auction bots

Option 2: Full On-Chain Governance

Deploy with complete governance infrastructure:
(Folio folio, address proxyAdmin) = folioDeployer.deployGovernedFolio(
    IVotes(address(0)),     // Self-governed (creates vote-locked token)
    basicDetails,
    additionalDetails,
    flags,
    ownerGovParams,         // Parameters for owner governance
    tradingGovParams,       // Parameters for trading governance
    govRoles,
    deploymentNonce
);
Use cases:
  • Community-governed Folios
  • Transparent decision-making
  • Token-holder voting
  • Decentralized management

Configuring Owner Governance

Owner governance controls admin functions (fees, roles, deprecation).
1

Set Voting Parameters

IGovernanceDeployer.GovParams memory ownerGovParams = IGovernanceDeployer.GovParams({
    votingDelay: 1 days,           // Time before voting starts
    votingPeriod: 7 days,          // How long voting lasts
    proposalThreshold: 10_000e18,  // Min tokens to create proposal
    quorumThreshold: 10,           // Required quorum (10%)
    timelockDelay: 2 days,         // Delay before execution
    guardians: [guardianAddress]   // Can cancel malicious proposals
});
Parameter Guidance:
  • votingDelay: Prevents surprise proposals, allows token acquisition
  • votingPeriod: Balance between speed and participation
  • proposalThreshold: Prevents spam, should be achievable
  • quorumThreshold: Percentage of total supply (not circulating)
  • timelockDelay: Allows users to exit before changes take effect
  • guardians: Trusted addresses for emergency cancellation
2

Choose Voting Token

Option A: Self-Governance (Folio shares = voting power)
IVotes stToken = IVotes(address(0)); // Deploy new vote-locked token
This creates a StakingVault where users stake Folio shares to get voting power.Option B: Existing Token
IVotes stToken = IVotes(existingGovernanceToken);
Use an existing ERC20Votes token for governance.
3

Deploy Governance

(address governor, address timelock) = governanceDeployer.deployGovernanceWithTimelock(
    ownerGovParams,
    stToken,
    deploymentSalt
);

// Grant admin role to timelock
folio.grantRole(folio.DEFAULT_ADMIN_ROLE(), timelock);
Deployed components:
  • Governor: Handles proposals and voting
  • Timelock: Queues and executes approved actions

Configuring Trading Governance

Trading governance controls rebalancing operations.
1

Set Rebalancing Parameters

IGovernanceDeployer.GovParams memory tradingGovParams = IGovernanceDeployer.GovParams({
    votingDelay: 6 hours,        // Faster for trading decisions
    votingPeriod: 3 days,        // Shorter voting period
    proposalThreshold: 5_000e18, // Lower threshold
    quorumThreshold: 5,          // 5% quorum
    timelockDelay: 1 days,       // Shorter delay for market responsiveness
    guardians: [guardianAddress]
});
Trading governance typically has shorter timelines than owner governance to respond to market conditions.
2

Configure Role Assignment

IFolioDeployer.GovRoles memory govRoles = IFolioDeployer.GovRoles({
    existingBasketManagers: new address[](0), // Empty = deploy trading gov
    auctionLaunchers: [botAddress],           // EOA or automation contract
    brandManagers: []
});
Two approaches:
  1. Governance-controlled: Leave existingBasketManagers empty to deploy a separate trading governor
  2. Direct control: Provide addresses to skip trading governance deployment
3

Grant Rebalance Role

If using governance:
// Automatically done by deployGovernedFolio
folio.grantRole(REBALANCE_MANAGER, tradingTimelock);
If using direct control:
folio.grantRole(REBALANCE_MANAGER, tradingMultisig);

Managing Staking Vaults

When self-governing, a StakingVault is deployed for vote locking.

Staking Folio Shares

// Users stake Folio shares to get voting power
folio.approve(address(stakingVault), amount);
stakingVault.stake(amount, recipient);

// Staking returns vote-locked shares (stFolio)
// stFolio balance = voting power

Unstaking

// Initiate unstaking (starts cooldown period)
stakingVault.unstake(amount);

// Wait for unstaking delay (default: 1 week)
// Then withdraw
stakingVault.withdraw();

Delegation

// Delegate voting power without transferring tokens
stakingVault.delegate(delegateAddress);

// Check delegation
uint256 delegatedVotes = stakingVault.getVotes(delegateAddress);
The StakingVault has:
  • Reward period: 3.5 days (for reward distribution)
  • Unstaking delay: 1 week (security cooldown)

Creating Governance Proposals

1

Prepare Proposal Actions

// Example: Change mint fee to 0.5%
address[] memory targets = new address[](1);
targets[0] = address(folio);

uint256[] memory values = new uint256[](1);
values[0] = 0; // No ETH transfer

bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSelector(
    folio.setMintFee.selector,
    0.005e18 // 0.5%
);

string memory description = "Lower mint fee to 0.5% to encourage adoption";
2

Submit Proposal

uint256 proposalId = governor.propose(
    targets,
    values,
    calldatas,
    description
);
Ensure the proposer has at least proposalThreshold tokens.
3

Vote on Proposal

After the voting delay:
// 0 = Against, 1 = For, 2 = Abstain
governor.castVote(proposalId, 1);

// Or with reason
governor.castVoteWithReason(proposalId, 1, "I support this change");
4

Queue and Execute

After voting period ends and proposal succeeds:
// Queue in timelock
governor.queue(
    targets,
    values,
    calldatas,
    keccak256(bytes(description))
);

// Wait for timelock delay
// Then execute
governor.execute(
    targets,
    values,
    calldatas,
    keccak256(bytes(description))
);

Example Governance Actions

Update Fees

// Proposal to change TVL fee
calldatas[0] = abi.encodeWithSelector(
    folio.setTVLFee.selector,
    634195839675290 // ~2% annual
);

Add Fee Recipient

IFolio.FeeRecipient[] memory newRecipients = new IFolio.FeeRecipient[](2);
newRecipients[0] = IFolio.FeeRecipient(treasury, 0.7e18);
newRecipients[1] = IFolio.FeeRecipient(devFund, 0.3e18);

calldatas[0] = abi.encodeWithSelector(
    folio.setFeeRecipients.selector,
    newRecipients
);

Start Rebalance

// Proposal to rebalance basket
IFolio.TokenRebalanceParams[] memory tokens = ...;
IFolio.RebalanceLimits memory limits = ...;

calldatas[0] = abi.encodeWithSelector(
    folio.startRebalance.selector,
    tokens,
    limits,
    3 days,  // Auction launcher window
    7 days   // TTL
);

Grant Role

// Add new auction launcher
calldatas[0] = abi.encodeWithSelector(
    folio.grantRole.selector,
    AUCTION_LAUNCHER,
    newBotAddress
);

Guardian Emergency Powers

Guardians can cancel malicious or erroneous proposals:
// Guardian cancels proposal via timelock
timelock.cancel(proposalId);
Guardians have significant power. Choose trusted, security-conscious addresses. Consider using a multi-guardian setup.

Best Practices

Use different governance structures for different roles:
  • Owner governance: Long timelock, high quorum (protocol safety)
  • Trading governance: Shorter timelock, lower quorum (market responsiveness)
  • Auction launcher: Automated EOA or bot (execution efficiency)
Start with multisig control, then gradually transition to on-chain governance as the community matures:
  1. Launch: Multisig for all roles
  2. Growth: On-chain trading governance, multisig owner governance
  3. Maturity: Full on-chain governance with guardians
  • 2+ days for owner governance: Allows users to exit before major changes
  • 1 day for trading governance: Balance between security and responsiveness
  • Never 0: Always have some delay for transparency
Calculate based on:
  • Expected participation rates (typically 5-20%)
  • Token distribution (whale concentration vs broad distribution)
  • Proposal importance (higher quorum for critical changes)

Monitoring Governance

Check Current Configuration

// View role holders
uint256 adminCount = folio.getRoleMemberCount(folio.DEFAULT_ADMIN_ROLE());
address admin = folio.getRoleMember(folio.DEFAULT_ADMIN_ROLE(), 0);

// View governance parameters
uint256 votingDelay = governor.votingDelay();
uint256 votingPeriod = governor.votingPeriod();
uint256 proposalThreshold = governor.proposalThreshold();
uint256 quorum = governor.quorum(block.number - 1);

Track Proposals

// Get proposal state
IGovernor.ProposalState state = governor.state(proposalId);
// States: Pending, Active, Canceled, Defeated, Succeeded, Queued, Expired, Executed

// Check votes
(uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) = governor.proposalVotes(proposalId);

Code Reference

  • Governance deployer: contracts/deployer/GovernanceDeployer.sol:40-109
  • Governor implementation: contracts/governance/FolioGovernor.sol
  • Staking vault: contracts/staking/StakingVault.sol
  • Role constants: contracts/utils/Constants.sol

Next Steps

Managing Rebalances

Use governance to start and manage rebalances

Deploying Folio

Review deployment options with governance

Build docs developers (and LLMs) love