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.
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.
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