Rewarder Module

Implements liquidity mining rewards to incentivize liquidity provision.

Core Data Structures

RewarderManager

The main controller that manages all rewarders for a pool:

struct RewarderManager {
    rewarders: vector<Rewarder>,      // Up to 5 rewarders
    points_released: u128,             // Total points released over time
    points_growth_global: u128,        // Global points growth rate
    last_updated_time: u64,           // Last settlement timestamp
}

Rewarder

Individual rewarder configuration for a specific reward token:

struct Rewarder {
    reward_coin: TypeName,            // Type of reward token
    emissions_per_second: u128,       // Emission rate (tokens per second)
    growth_global: u128,              // Accumulated growth factor
}

RewarderGlobalVault

Centralized storage for all reward token balances:

struct RewarderGlobalVault {
    id: UID,
    balances: Bag,                    // Stores Balance<T> for each reward token
}

Core Functionality

Initialization

The module automatically creates a shared RewarderGlobalVault during initialization:

fun init(ctx: &mut TxContext)

This vault serves as the central repository for all reward tokens across all pools.

Rewarder Management

Adding a New Rewarder

public(friend) fun add_rewarder<CoinType>(manager: &mut RewarderManager)
  • Adds a new rewarder for the specified CoinType

  • Validates that the coin type doesn't already exist

  • Enforces the maximum limit of 5 rewarders per pool

  • Initializes with zero emissions (must be configured separately)

Updating Emission Rates

public(friend) fun update_emission<CoinType>(
    vault: &RewarderGlobalVault,
    manager: &mut RewarderManager,
    liquidity: u128,
    new_emissions: u128,
    current_time: u64
)
  • Updates the emission rate for a specific rewarder

  • Automatically settles pending rewards before updating

  • Validates sufficient balance for 24 hours of rewards at the new rate

  • Requires vault balance ≥ 86400 * new_emissions for rate increases

Reward Distribution

Settlement Process

public(friend) fun settle(
    manager: &mut RewarderManager,
    liquidity: u128,
    current_time: u64
)

The settlement process:

  1. Time Validation: Ensures time progression is valid

  2. Liquidity Check: Skips settlement if no liquidity or no time passed

  3. Growth Calculation: For each rewarder with non-zero emissions:

    growth_increase = (time_delta * emissions_per_second) / liquidity
  4. Points Update: Updates global points tracking using a constant multiplier

Token Management

Depositing Rewards

public fun deposit_reward<CoinType>(
    global_config: &GlobalConfig,
    vault: &mut RewarderGlobalVault,
    reward: Balance<CoinType>
) : u64
  • Adds reward tokens to the global vault

  • Creates new balance entry if token type doesn't exist

  • Emits DepositEvent for tracking

  • Returns the final balance amount

Emergency Withdrawal

public fun emergent_withdraw<CoinType>(
    _admin_cap: &AdminCap,
    global_config: &GlobalConfig,
    vault: &mut RewarderGlobalVault,
    amount: u64
) : Balance<CoinType>
  • Admin-only function for emergency token withdrawal

  • Requires AdminCap authorization

  • Emits EmergentWithdrawEvent for auditability

API Reference

Query Functions

Balance Queries

// Get balance of specific token type in vault
public fun balance_of<CoinType>(vault: &RewarderGlobalVault) : u64

// Get reference to all balances
public fun balances(vault: &RewarderGlobalVault) : &Bag

Rewarder Information

// Get rewarder index for a coin type
public fun rewarder_index<CoinType>(manager: &RewarderManager) : Option<u64>

// Get all rewarders
public fun rewarders(manager: &RewarderManager) : vector<Rewarder>

// Get growth values for all rewarders
public fun rewards_growth_global(manager: &RewarderManager) : vector<u128>

Individual Rewarder Data

// Access specific rewarder (read-only)
public fun borrow_rewarder<CoinType>(manager: &RewarderManager) : &Rewarder

// Get emission rate
public fun emissions_per_second(rewarder: &Rewarder) : u128

// Get growth global value
public fun growth_global(rewarder: &Rewarder) : u128

// Get reward coin type
public fun reward_coin(rewarder: &Rewarder) : TypeName

Manager State

// Get last update timestamp
public fun last_update_time(manager: &RewarderManager) : u64

// Get global points data
public fun points_growth_global(manager: &RewarderManager) : u128
public fun points_released(manager: &RewarderManager) : u128

Friend Functions

These functions are restricted to the ferra_clmm::pool module:

// Create new manager
public(friend) fun new() : RewarderManager

// Add rewarder
public(friend) fun add_rewarder<CoinType>(manager: &mut RewarderManager)

// Access mutable rewarder
public(friend) fun borrow_mut_rewarder<CoinType>(manager: &mut RewarderManager) : &mut Rewarder

// Settle rewards
public(friend) fun settle(manager: &mut RewarderManager, liquidity: u128, current_time: u64)

// Update emissions
public(friend) fun update_emission<CoinType>(/*...*/)

// Withdraw rewards
public(friend) fun withdraw_reward<CoinType>(vault: &mut RewarderGlobalVault, amount: u64) : Balance<CoinType>

Events

RewarderInitEvent

Emitted during module initialization:

struct RewarderInitEvent {
    global_vault_id: ID,
}

DepositEvent

Emitted when rewards are deposited:

struct DepositEvent {
    reward_type: TypeName,
    deposit_amount: u64,
    after_amount: u64,
}

EmergentWithdrawEvent

Emitted during emergency withdrawals:

struct EmergentWithdrawEvent {
    reward_type: TypeName,
    withdraw_amount: u64,
    after_amount: u64,
}

Error Codes

  • Error 1: Maximum number of rewarders exceeded (limit: 5)

  • Error 2: Rewarder for this coin type already exists

  • Error 3: Invalid time progression (current_time < last_updated_time)

  • Error 4: Insufficient balance in vault for new emission rate

  • Error 5: Rewarder not found for the specified coin type

Mathematical Formulas

Growth Calculation

For each rewarder during settlement:

growth_increase = mul_div_floor(time_delta, emissions_per_second, liquidity)
new_growth_global = old_growth_global + growth_increase

Points Calculation

Using a constant multiplier (2^64 * 10^6):

multiple = 18446744073709551616000000
points_released += time_delta * multiple
points_growth_global += mul_div_floor(time_delta, multiple, liquidity)

Balance Validation

For emission rate increases:

required_balance = 86400 * new_emissions  // 24 hours worth
current_balance_scaled = balance << 64     // Scaled for precision
assert(current_balance_scaled >= required_balance)

Best Practices

  1. Regular Settlement: Settle rewards before major pool operations

  2. Sufficient Funding: Maintain adequate vault balances for sustained rewards

  3. Gradual Rate Changes: Avoid sudden large emission rate changes

  4. Monitor Events: Track all reward-related events for proper accounting

  5. Emergency Procedures: Have clear protocols for emergency withdrawals

Last updated