Token Economics

A comprehensive guide to implementing robust token economics for your liquid staking protocol on Solana, including exchange rates, fees, rewards, and incentive mechanisms.

Last updated: 2024-03-21
Edit on GitHub

Overview

Token economics is a crucial aspect of your liquid staking protocol that determines its sustainability, user incentives, and overall success. This guide covers exchange rate mechanisms, fee structures, reward distribution, and incentive design.

Token Economics Flow

Exchange Rate Mechanism

Implement a robust exchange rate mechanism that accurately reflects the value of staked SOL and handles rewards accumulation.

Exchange Rate Implementation

1pub struct ExchangeRate {
2    /// Total SOL staked (including rewards)
3    pub total_sol_balance: u64,
4    
5    /// Total stSOL supply
6    pub total_st_sol_supply: u64,
7    
8    /// Last update epoch
9    pub last_update_epoch: u64,
10    
11    /// Minimum rate (1 stSOL = 1 SOL)
12    pub min_rate: u64,
13}
14
15impl ExchangeRate {
16    pub fn calculate_rate(&self) -> Result<f64, ProgramError> {
17        if self.total_st_sol_supply == 0 {
18            return Ok(1.0);
19        }
20        
21        let rate = (self.total_sol_balance as f64) / (self.total_st_sol_supply as f64);
22        Ok(rate.max(1.0)) // Rate cannot go below 1:1
23    }
24    
25    pub fn sol_to_st_sol(&self, sol_amount: u64) -> Result<u64, ProgramError> {
26        let rate = self.calculate_rate()?;
27        Ok((sol_amount as f64 / rate) as u64)
28    }
29    
30    pub fn st_sol_to_sol(&self, st_sol_amount: u64) -> Result<u64, ProgramError> {
31        let rate = self.calculate_rate()?;
32        Ok((st_sol_amount as f64 * rate) as u64)
33    }
34    
35    pub fn update_with_rewards(&mut self, rewards: u64) -> ProgramResult {
36        // Add rewards to total balance
37        self.total_sol_balance = self.total_sol_balance
38            .checked_add(rewards)
39            .ok_or(StakePoolError::CalculationFailure)?;
40            
41        // Update epoch
42        self.last_update_epoch = Clock::get()?.epoch;
43        
44        Ok(())
45    }
46}

Fee Structure

Design and implement a sustainable fee structure that balances protocol revenue with user incentives.

Fee Structure Implementation

1pub struct FeeSchedule {
2    /// Protocol fee percentage (basis points)
3    pub protocol_fee_bp: u16,
4    
5    /// Treasury fee percentage (basis points)
6    pub treasury_fee_bp: u16,
7    
8    /// Validator commission (basis points)
9    pub validator_commission_bp: u16,
10    
11    /// Deposit fee percentage (basis points)
12    pub deposit_fee_bp: u16,
13    
14    /// Withdrawal fee percentage (basis points)
15    pub withdrawal_fee_bp: u16,
16}
17
18impl FeeSchedule {
19    pub fn calculate_reward_fees(
20        &self,
21        reward_amount: u64,
22    ) -> Result<FeeBreakdown, ProgramError> {
23        // Calculate protocol fee
24        let protocol_fee = calculate_basis_points(
25            reward_amount,
26            self.protocol_fee_bp,
27        )?;
28        
29        // Calculate treasury fee
30        let treasury_fee = calculate_basis_points(
31            reward_amount,
32            self.treasury_fee_bp,
33        )?;
34        
35        // Calculate validator commission
36        let validator_commission = calculate_basis_points(
37            reward_amount,
38            self.validator_commission_bp,
39        )?;
40        
41        // Calculate user rewards
42        let user_rewards = reward_amount
43            .checked_sub(protocol_fee)?
44            .checked_sub(treasury_fee)?
45            .checked_sub(validator_commission)?;
46            
47        Ok(FeeBreakdown {
48            protocol_fee,
49            treasury_fee,
50            validator_commission,
51            user_rewards,
52        })
53    }
54    
55    pub fn calculate_deposit_fee(&self, amount: u64) -> Result<u64, ProgramError> {
56        calculate_basis_points(amount, self.deposit_fee_bp)
57    }
58    
59    pub fn calculate_withdrawal_fee(&self, amount: u64) -> Result<u64, ProgramError> {
60        calculate_basis_points(amount, self.withdrawal_fee_bp)
61    }
62}
63
64fn calculate_basis_points(amount: u64, basis_points: u16) -> Result<u64, ProgramError> {
65    Ok(((amount as u128)
66        .checked_mul(basis_points as u128)
67        .ok_or(StakePoolError::CalculationFailure)?
68        .checked_div(10000)
69        .ok_or(StakePoolError::CalculationFailure)?) as u64)
70}

Reward Distribution

Implement efficient reward collection and distribution mechanisms.

Reward Distribution Implementation

1pub struct RewardDistributor {
2    /// Minimum distribution amount
3    pub min_distribution: u64,
4    
5    /// Distribution frequency (epochs)
6    pub distribution_frequency: u64,
7    
8    /// Last distribution epoch
9    pub last_distribution: u64,
10    
11    /// Fee schedule
12    pub fee_schedule: FeeSchedule,
13}
14
15impl RewardDistributor {
16    pub async fn distribute_rewards(
17        &mut self,
18        stake_pool: &mut StakePool,
19    ) -> ProgramResult {
20        let current_epoch = Clock::get()?.epoch;
21        
22        // Check if distribution is needed
23        if current_epoch.saturating_sub(self.last_distribution)
24            < self.distribution_frequency {
25            return Ok(());
26        }
27        
28        // Collect rewards from validators
29        let total_rewards = self.collect_validator_rewards(stake_pool).await?;
30        
31        // Check minimum distribution
32        if total_rewards < self.min_distribution {
33            return Ok(());
34        }
35        
36        // Calculate fee breakdown
37        let fees = self.fee_schedule.calculate_reward_fees(total_rewards)?;
38        
39        // Update exchange rate with user rewards
40        stake_pool.exchange_rate.update_with_rewards(fees.user_rewards)?;
41        
42        // Transfer fees
43        self.transfer_protocol_fee(fees.protocol_fee)?;
44        self.transfer_treasury_fee(fees.treasury_fee)?;
45        self.transfer_validator_commission(fees.validator_commission)?;
46        
47        // Update distribution state
48        self.last_distribution = current_epoch;
49        
50        // Emit distribution event
51        emit!(RewardsDistributed {
52            stake_pool: stake_pool.pubkey(),
53            total_rewards,
54            fee_breakdown: fees,
55            epoch: current_epoch,
56        });
57        
58        Ok(())
59    }
60}

Incentive Mechanisms

Design and implement incentive mechanisms to encourage desired behaviors.

Incentive Mechanism Implementation

1pub struct IncentiveMechanism {
2    /// Early withdrawal penalty (basis points)
3    pub early_withdrawal_penalty_bp: u16,
4    
5    /// Minimum stake duration for no penalty
6    pub min_stake_duration: u64,
7    
8    /// Loyalty bonus schedule
9    pub loyalty_bonus_schedule: Vec<(u64, u16)>, // (duration, bonus_bp)
10    
11    /// Referral rewards (basis points)
12    pub referral_reward_bp: u16,
13}
14
15impl IncentiveMechanism {
16    pub fn calculate_withdrawal_penalty(
17        &self,
18        amount: u64,
19        stake_duration: u64,
20    ) -> Result<u64, ProgramError> {
21        if stake_duration >= self.min_stake_duration {
22            return Ok(0);
23        }
24        
25        // Calculate penalty based on early withdrawal
26        let penalty_multiplier = (self.min_stake_duration - stake_duration) as f64
27            / self.min_stake_duration as f64;
28            
29        let penalty = ((amount as u128)
30            .checked_mul(self.early_withdrawal_penalty_bp as u128)
31            .ok_or(StakePoolError::CalculationFailure)?
32            .checked_mul(penalty_multiplier as u128)
33            .ok_or(StakePoolError::CalculationFailure)?
34            .checked_div(10000)
35            .ok_or(StakePoolError::CalculationFailure)?) as u64;
36            
37        Ok(penalty)
38    }
39    
40    pub fn calculate_loyalty_bonus(
41        &self,
42        amount: u64,
43        stake_duration: u64,
44    ) -> Result<u64, ProgramError> {
45        // Find applicable bonus tier
46        let bonus_bp = self.loyalty_bonus_schedule
47            .iter()
48            .rev()
49            .find(|(min_duration, _)| stake_duration >= *min_duration)
50            .map(|(_, bonus)| *bonus)
51            .unwrap_or(0);
52            
53        calculate_basis_points(amount, bonus_bp)
54    }
55    
56    pub fn calculate_referral_reward(
57        &self,
58        deposit_amount: u64,
59    ) -> Result<u64, ProgramError> {
60        calculate_basis_points(deposit_amount, self.referral_reward_bp)
61    }
62}

Token Supply Management

Implement secure token supply management with minting and burning controls.

Token Supply Management

1pub struct TokenSupplyManager {
2    /// Pool token mint
3    pub pool_mint: Pubkey,
4    
5    /// Mint authority
6    pub mint_authority: Pubkey,
7    
8    /// Maximum supply cap (optional)
9    pub max_supply: Option<u64>,
10    
11    /// Minimum mint amount
12    pub min_mint_amount: u64,
13}
14
15impl TokenSupplyManager {
16    pub fn mint_tokens(
17        &self,
18        amount: u64,
19        destination: &Pubkey,
20    ) -> ProgramResult {
21        // Check minimum mint amount
22        if amount < self.min_mint_amount {
23            return Err(StakePoolError::AmountTooSmall.into());
24        }
25        
26        // Check supply cap if set
27        if let Some(max_supply) = self.max_supply {
28            let current_supply = self.get_current_supply()?;
29            if current_supply.checked_add(amount)
30                .ok_or(StakePoolError::CalculationFailure)?
31                > max_supply {
32                return Err(StakePoolError::SupplyCapExceeded.into());
33            }
34        }
35        
36        // Create mint instruction
37        let mint_ix = spl_token::instruction::mint_to(
38            &spl_token::id(),
39            &self.pool_mint,
40            destination,
41            &self.mint_authority,
42            &[],
43            amount,
44        )?;
45        
46        // Process instruction
47        invoke_signed(
48            &mint_ix,
49            &[/* account infos */],
50            &[/* seeds */],
51        )?;
52        
53        Ok(())
54    }
55    
56    pub fn burn_tokens(
57        &self,
58        amount: u64,
59        source: &Pubkey,
60        authority: &Pubkey,
61    ) -> ProgramResult {
62        // Create burn instruction
63        let burn_ix = spl_token::instruction::burn(
64            &spl_token::id(),
65            source,
66            &self.pool_mint,
67            authority,
68            &[],
69            amount,
70        )?;
71        
72        // Process instruction
73        invoke_signed(
74            &burn_ix,
75            &[/* account infos */],
76            &[/* seeds */],
77        )?;
78        
79        Ok(())
80    }
81}
Economic Considerations
  • Ensure exchange rate cannot decrease to protect staker value
  • Design sustainable fee structures that cover operational costs
  • Implement gradual fee changes to avoid market disruption
  • Consider implementing fee caps to remain competitive
  • Design incentives to encourage long-term staking
  • Maintain transparent reward distribution mechanisms