Fee Collector¶
Overview¶
The FeeCollector is the central contract for managing protocol fee collection and distribution across the RAAC ecosystem. It handles fee collection from various protocol activities and distributes them according to configurable splits to different stakeholders including treasury, repair fund, veRAAC holders, and other designated recipients.
Purpose¶
- Centralized Fee Management: Collect fees from all protocol activities in a unified manner
- Configurable Distribution: Split collected fees across multiple stakeholders based on predefined percentages
- Multi-Token Support: Handle fee collection in different supported tokens (scrvUSD, crvUSD, iRAAC)
- Role-Based Access Control: Secure management through distinct roles for different operations
- Emergency Controls: Pause functionality and emergency withdrawal capabilities
Architecture¶
flowchart TD
A[Protocol Activities] -->|collectFee| B[FeeCollector]
B -->|Fee Split| C[Treasury]
B -->|Fee Split| D[Repair Fund]
B -->|Fee Split| E[Burn Address]
B -->|Fee Split| F[veRAAC Holders]
B -->|Fee Split| G[RAAC Corp]
B -->|Fee Split| H[Other Targets]
I[Fee Types] -->|Configure| B
J[Supported Tokens] -->|Whitelist| B
K[Distribution Targets] -->|Whitelist| B
Supported Tokens¶
The FeeCollector accepts fees in the following whitelisted tokens:
Token | Description |
---|---|
scrvUSD | Curve SCRVUSD vault shares |
crvUSD | Curve USD stablecoin |
iRAAC | RAAC index token from RWA Vault |
Approval Security
We strongly advise against giving type(uint256).max
approval to the FeeCollector.
Instead, approve only the specific amount needed for fee collection to minimize security risks.
CRITICAL: Pull-Based System - Direct Transfers Result in Permanent Loss
The FeeCollector is a pull-based system that does NOT track direct token transfers.
Any direct transfer of tokens to the FeeCollector address will result in PERMANENT LOSS of funds.
The contract only tracks and accounts for fees collected through the collectFee()
function.
NEVER send tokens directly to the FeeCollector address.
Fee Types & Distribution¶
Fees are collected by fee type and distributed according to configurable percentages across six target categories:
Target | Description | Configurable |
---|---|---|
Treasury | Protocol treasury for general operations | YES |
Repair Fund | Safety fund for protocol maintenance | YES |
Burn | Token burn mechanism | YES |
veRAAC | Rewards for veRAAC token holders | YES |
RAAC Corp | Corporate allocation | YES |
Other | Additional designated recipients | YES |
Fee Type Configuration
Each fee type must have percentages that sum to exactly 100% (10,000 basis points).
For detailed parameter configuration, refer to the Parameters page.
Dust and Rounding Handling
If the total distribution for a fee type is not exactly 100% due to rounding or configuration errors, any remaining amount (including dust) is automatically sent to the treasury. This ensures that all collected fees are properly distributed and no funds are left unallocated.
Key Functions¶
collectFee
¶
collectFee(address token, address target, uint256 amount, bytes32 feeType) → bool
Summary
Collects fees of a specific type from a target contract. This is the primary public method for fee collection across the protocol.
Guarded Method
- Callable by any address (typically protocol contracts)
- Protected by nonReentrant
, whenNotPaused
, and validation checks
Parameters
Name | Type | Description |
---|---|---|
token | address |
Token address to collect fees in (must be whitelisted) |
target | address |
Address to collect fees from (must approve FeeCollector) |
amount | uint256 |
Amount of tokens to collect |
feeType | bytes32 |
Type of fee being collected (must be configured) |
Returns
bool
— true
if collection successful
Emits
- FeeCollected(address indexed token, address indexed target, bytes32 indexed feeType, uint256 amount, uint256 actualAmount)
Reverts
InvalidFeeAmount()
— ifamount == 0
FeeTypeDoesNotExist()
— if fee type not configuredTokenNotSupported()
— if token not whitelisted- ERC20 transfer failures
Requirements
- Target must have approved FeeCollector to spend tokens
- Token must be in supported tokens list
- Fee type must be configured with valid percentages
- Handles fee-on-transfer tokens by measuring actual received amount
Example (TypeScript / ethers)
Source code
function collectFee(address token, address target, uint256 amount, bytes32 feeType)
external
nonReentrant
whenNotPaused
returns (bool)
{
if (amount == 0) revert InvalidFeeAmount();
if (feeTypes[feeType].feeType == bytes32(0)) revert FeeTypeDoesNotExist();
if (!isTokenSupported[token]) revert TokenNotSupported();
// Transfer tokens from target to this contract
uint256 balanceBefore = IERC20(token).balanceOf(address(this));
IERC20(token).safeTransferFrom(target, address(this), amount);
uint256 balanceAfter = IERC20(token).balanceOf(address(this));
// Handle fee-on-transfer tokens
uint256 actualAmount = balanceAfter - balanceBefore;
// Update collected fees for this token
_updateCollectedFees(token, feeType, actualAmount);
emit FeeCollected(token, target, feeType, amount, actualAmount);
return true;
}
Private Methods (Role-Protected)¶
Fee Management¶
Function | Role | Description |
---|---|---|
addFeeType |
FEE_MANAGER_ROLE |
Add new fee type with distribution percentages |
updateFeeType |
FEE_MANAGER_ROLE |
Update existing fee type configuration |
removeFeeType |
FEE_MANAGER_ROLE |
Remove fee type (after distribution) |
setTargetFeeType |
FEE_MANAGER_ROLE |
Assign fee type to specific target |
removeTargetFeeType |
FEE_MANAGER_ROLE |
Remove fee type assignment from target |
Token & Target Management¶
Function | Role | Description |
---|---|---|
addClaimableToken |
FEE_MANAGER_ROLE |
Add token to supported tokens list |
removeClaimableToken |
FEE_MANAGER_ROLE |
Remove token from supported tokens list |
addWhitelistedTarget |
FEE_MANAGER_ROLE |
Add target to whitelist for fee collection |
removeWhitelistedTarget |
FEE_MANAGER_ROLE |
Remove target from whitelist |
setTargetAddress |
FEE_MANAGER_ROLE |
Set address for distribution targets |
Distribution & Collection¶
Function | Role | Description |
---|---|---|
distributeFees |
DISTRIBUTOR_ROLE |
Distribute collected fees to specific target |
claimCollectorRewards |
FEE_MANAGER_ROLE |
Claim rewards from whitelisted targets |
claimNFTUnderlying |
FEE_MANAGER_ROLE |
Claim underlying assets from wrapped tokens |
Emergency Controls¶
Function | Role | Description |
---|---|---|
pause |
EMERGENCY_ROLE |
Pause all contract operations |
unpause |
EMERGENCY_ROLE |
Resume contract operations |
emergencyWithdraw |
EMERGENCY_ROLE |
Emergency withdrawal of all tokens |
Public Read Methods¶
Target Information¶
Function | Returns | Description |
---|---|---|
getTargetAddress(bytes32 target) |
address |
Get address for specific target type |
getTargetAmount(bytes32 feeType, bytes32 target, address token) |
uint256 |
Get collected amount for target |
Fee Type Information¶
Function | Returns | Description |
---|---|---|
getFeeType(bytes32 feeType) |
FeeType |
Get fee type configuration |
getFeeTypes() |
FeeType[] |
Get all fee type configurations |
Collected Fees¶
Function | Returns | Description |
---|---|---|
getCollectedFees(address token, bytes32 feeType) |
CollectedFeeForType |
Get collected fees for token/fee type |
Configuration Status¶
Function | Returns | Description |
---|---|---|
isTokenSupported(address token) |
bool |
Check if token is whitelisted |
isTargetWhitelisted(address target) |
bool |
Check if target is whitelisted |
isValidDistributionTarget(address target) |
bool |
Check if target supports distribution interface |
Fee Distribution Flow¶
- Collection: Protocol contracts call
collectFee()
with appropriate fee type - Splitting: Fees are automatically split according to fee type percentages
- Storage: Split amounts are stored in
collectedFeesByToken
mapping - Distribution: Authorized distributors call
distributeFees()
to send funds to targets - Tracking: All distributions are tracked and amounts are reduced accordingly
Access Control Roles¶
Role | Permissions |
---|---|
DEFAULT_ADMIN_ROLE |
Full administrative control, can grant/revoke all roles |
FEE_MANAGER_ROLE |
Configure fee types, manage tokens/targets, claim rewards |
DISTRIBUTOR_ROLE |
Execute fee distributions to targets |
EMERGENCY_ROLE |
Pause/unpause contract, emergency withdrawals |
Integration Notes¶
- Protocol Contracts: Should call
collectFee()
after collecting fees from users - Target Contracts: Must implement
IDistributionTarget
interface for automated distribution - Fee Types: Must be pre-configured before collection can begin
- Token Support: Only whitelisted tokens can be used for fee collection
For detailed parameter configuration and current fee type settings, refer to the Parameters page.