Page cover

Fee Collector

The FeeCollector is a fee management contract that handles the calculation, collection, and distribution of fees in the Genius bridge protocol. It implements a multi-tier fee structure with separate fee types for protocol maintenance, liquidity providers, and operators, ensuring sustainable protocol economics while incentivizing all participants.

The contract serves as the central hub for all fee-related operations, providing transparent fee calculation, secure fee collection, and automated distribution to various stakeholders. It supports dynamic fee tiers based on order size and maintains separate accounting for different fee types.

The FeeCollector contract - overview

The FeeCollector contract is an upgradeable contract that implements a comprehensive fee management system. It calculates fees based on order size using tiered structures, collects fees from the vault during order creation, and distributes them to designated receivers based on role-based access control.

The contract maintains separate accounting for protocol fees, liquidity provider (LP) fees, and operator fees, ensuring transparent tracking and secure distribution to the appropriate stakeholders.

The FeeCollector contract - key features

Multi-tier fee structure

The contract implements sophisticated fee tiers based on order size, allowing for dynamic fee calculation that scales with transaction volume. This ensures that larger orders contribute proportionally more to protocol sustainability while keeping fees reasonable for smaller transactions.

Separate fee types

The contract manages three distinct fee types:

  • Protocol fees: Allocated to protocol maintenance and development

  • LP fees: Distributed to liquidity providers as incentives

  • Operator fees: Compensates operators for cross-chain execution work

Role-based fee distribution

Different fee types are distributed to different roles:

  • Admin: Can claim protocol fees for the designated receiver

  • Distributor: Can claim LP fees for liquidity providers

  • Worker: Can claim operator fees for operators

Chain-specific minimum fees

Each destination chain has its own minimum fee requirement, accounting for different gas costs and operational expenses across different blockchain networks.

Insurance fee calculation

The contract calculates insurance fees separately from other fees, which are retained in the vault as additional liquidity protection against reorgs and rebalancing fees.

Comprehensive fee tracking

All fees are tracked with separate accounting for collected and claimed amounts, providing full transparency and preventing double-spending.

Upgradeable architecture

The contract uses the UUPS upgradeable pattern, allowing for future improvements to the fee structure without disrupting existing operations.

Understanding the workflow of FeeCollector

  1. Initialization: The contract is initialized with admin address, stablecoin, fee percentages, and receiver addresses.

  2. Fee Calculation: When an order is created, the vault calls collectFromVault() to calculate the complete fee breakdown based on order size and destination chain.

  3. Fee Collection: The vault transfers the calculated fees to the FeeCollector, which distributes them into the appropriate fee buckets (protocol, LP, operator).

  4. Fee Distribution: Authorized roles can claim their respective fees by calling the appropriate claim functions:

    • claimProtocolFees() for admins

    • claimLPFees() for distributors

    • claimOperatorFees() for workers

  5. Fee Tracking: All fee movements are tracked and emitted as events for transparency and auditing purposes.

Core functions and their purposes

Fee Collection and Calculation

FeeCollector.sol
function collectFromVault(
    bytes32 _orderHash,
    uint256 _amountIn,
    uint256 _destChainId,
    uint256 _orderFee
) external returns (uint256 amountToTransfer) {
    if (msg.sender != vault) revert GeniusErrors.NotAuthorized();
    if (_amountIn == 0) revert GeniusErrors.InvalidAmount();

    // Calculate fee breakdown
    FeeBreakdown memory feeBreakdown = _calculateFeeBreakdown(
        _amountIn,
        _destChainId
    );

    // Check if the provided fee is sufficient
    if (_orderFee < feeBreakdown.totalFee)
        revert GeniusErrors.InsufficientFees(
            _orderFee,
            feeBreakdown.totalFee
        );

    // Calculate fee distribution based on percentages
    uint256 protocolFeeAmount = (feeBreakdown.bpsFee * protocolFee) /
        BASE_PERCENTAGE;
    uint256 lpFee = feeBreakdown.bpsFee - protocolFeeAmount;

    // Add fees to their respective buckets
    protocolFeesCollected += protocolFeeAmount;
    lpFeesCollected += lpFee;
    operatorFeesCollected += feeBreakdown.baseFee + feeSurplus;

    // The vault should transfer the total fee minus insurance fee to the fee collector
    amountToTransfer = _orderFee - feeBreakdown.insuranceFee;

    emit FeesCollectedFromVault(
        _orderHash,
        protocolFeeAmount,
        lpFee,
        feeBreakdown.baseFee + feeSurplus
    );
    return amountToTransfer;
}

Fee Breakdown Calculation

FeeCollector.sol
function _calculateFeeBreakdown(
    uint256 _amount,
    uint256 _destChainId
) internal view returns (FeeBreakdown memory) {
    uint256 baseFee = targetChainMinFee[_destChainId];

    if (baseFee == 0) {
        revert GeniusErrors.InvalidDestChainId(_destChainId);
    }

    // Calculate BPS fee
    uint256 bpsFeePercentage = _getBpsFeeForAmount(_amount);
    uint256 bpsFee = (_amount * bpsFeePercentage) / BASE_PERCENTAGE;

    // Calculate insurance fee
    uint256 insuranceFeePercentage = _getInsuranceFeeBpsForAmount(_amount);
    uint256 insuranceFee = (_amount * insuranceFeePercentage) /
        BASE_PERCENTAGE;

    // Calculate total fee
    uint256 totalFee = baseFee + bpsFee + insuranceFee;

    return FeeBreakdown({
        baseFee: baseFee,
        bpsFee: bpsFee,
        insuranceFee: insuranceFee,
        totalFee: totalFee
    });
}

Fee Claiming

FeeCollector.sol
function claimProtocolFees()
    external
    nonReentrant
    onlyAdmin
    returns (uint256 amount)
{
    amount = protocolFeesCollected - protocolFeesClaimed;
    if (amount == 0) revert GeniusErrors.InvalidAmount();
    if (protocolFeeReceiver == address(0))
        revert GeniusErrors.NonAddress0();

    protocolFeesClaimed += amount;
    stablecoin.safeTransfer(protocolFeeReceiver, amount);

    emit ProtocolFeesClaimed(msg.sender, protocolFeeReceiver, amount);
    return amount;
}

Tiered Fee Calculation

FeeCollector.sol
function _getBpsFeeForAmount(
    uint256 _amount
) internal view returns (uint256 bpsFee) {
    if (feeTiers.length == 0) return 0;

    // Default to the lowest tier fee
    bpsFee = feeTiers[0].bpsFee;

    // Find the highest tier that the amount qualifies for
    for (uint256 i = 0; i < feeTiers.length; i++) {
        if (_amount >= feeTiers[i].thresholdAmount) {
            bpsFee = feeTiers[i].bpsFee;
        } else {
            // Found a tier with threshold higher than amount, so break
            break;
        }
    }

    return bpsFee;
}

Fee structure and calculation

Fee Components

The total fee for an order consists of three components:

  1. Base Fee: A fixed minimum fee per destination chain, accounting for gas costs and operational expenses

  2. BPS Fee: A percentage-based fee calculated on the order amount, split between protocol and LP fees

  3. Insurance Fee: A percentage-based fee retained in the vault for additional liquidity protection

Fee Tiers

The contract supports dynamic fee tiers based on order size:

  • Threshold-based: Each tier has a minimum order size threshold

  • Ascending order: Tiers are ordered from smallest to largest threshold

  • Highest applicable: The highest tier that the order qualifies for is applied

Fee Distribution

  • Protocol fees: Calculated as (bpsFee * protocolFee) / BASE_PERCENTAGE

  • LP fees: Remaining BPS fees after protocol allocation

  • Operator fees: Base fee plus any surplus fees

Security features

Access Control

The contract implements comprehensive role-based access control:

  • Admin: Can manage all fee settings and claim protocol fees

  • Distributor: Can claim LP fees for liquidity providers

  • Worker: Can claim operator fees for operators

Reentrancy Protection

All fee claiming functions are protected against reentrancy attacks using OpenZeppelin's ReentrancyGuard.

Input Validation

Extensive validation ensures:

  • Valid addresses for all receivers

  • Proper fee percentages within acceptable bounds

  • Correct tier ordering and validation

  • Sufficient fees provided for orders

Vault Authorization

Only the authorized vault contract can call fee collection functions, preventing unauthorized fee manipulation.

Integration with other contracts

The FeeCollector interacts with several other contracts in the Genius ecosystem:

  • GeniusVault: Calls fee collection functions during order creation

  • Stablecoin Contracts: The underlying stablecoin used for fee payments

  • Fee Receivers: Various addresses that receive different fee types

Key state variables

  • stablecoin: The stablecoin token used for fee payments

  • vault: The authorized vault contract that can collect fees

  • protocolFee: Percentage of BPS fees allocated to protocol

  • feeTiers: Array of fee tiers based on order size

  • insuranceFeeTiers: Array of insurance fee tiers

  • targetChainMinFee: Mapping of chain ID to minimum fees

  • protocolFeesCollected / protocolFeesClaimed: Protocol fee accounting

  • lpFeesCollected / lpFeesClaimed: LP fee accounting

  • operatorFeesCollected / operatorFeesClaimed: Operator fee accounting

Events

The contract emits various events to track fee operations:

  • FeesCollectedFromVault: When fees are collected from the vault

  • ProtocolFeesClaimed: When protocol fees are claimed

  • LPFeesClaimed: When LP fees are claimed

  • OperatorFeesClaimed: When operator fees are claimed

  • ProtocolFeeReceiverSet: When protocol fee receiver is updated

  • LPFeeReceiverSet: When LP fee receiver is updated

  • OperatorFeeReceiverSet: When operator fee receiver is updated

  • FeeTiersUpdated: When fee tiers are updated

  • InsuranceFeeTiersUpdated: When insurance fee tiers are updated

  • TargetChainMinFeeChanged: When minimum fees for chains are updated

Fee management functions

Configuration Functions

  • setProtocolFeeReceiver(): Set the protocol fee receiver address

  • setLPFeeReceiver(): Set the LP fee receiver address

  • setOperatorFeeReceiver(): Set the operator fee receiver address

  • setProtocolFee(): Set the protocol fee percentage

  • setTargetChainMinFee(): Set minimum fees for specific chains

  • setFeeTiers(): Configure fee tiers based on order size

  • setInsuranceFeeTiers(): Configure insurance fee tiers

Query Functions

  • claimableProtocolFees(): Get claimable protocol fees

  • claimableLPFees(): Get claimable LP fees

  • claimableOperatorFees(): Get claimable operator fees

  • getOrderFees(): Calculate complete fee breakdown for an order

The FeeCollector is a critical component of the Genius protocol's economic model, ensuring sustainable revenue generation while maintaining transparency and fair distribution among all stakeholders. Its sophisticated fee structure and secure distribution mechanisms provide the foundation for long-term protocol viability.

Last updated