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:
Time Validation: Ensures time progression is valid
Liquidity Check: Skips settlement if no liquidity or no time passed
Growth Calculation: For each rewarder with non-zero emissions:
growth_increase = (time_delta * emissions_per_second) / liquidity
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 trackingReturns 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
authorizationEmits
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
Regular Settlement: Settle rewards before major pool operations
Sufficient Funding: Maintain adequate vault balances for sustained rewards
Gradual Rate Changes: Avoid sudden large emission rate changes
Monitor Events: Track all reward-related events for proper accounting
Emergency Procedures: Have clear protocols for emergency withdrawals
Last updated