quarry_mine/
lib.rs

1//! Liquidity mining rewards distribution program.
2//!
3//! The program consists of three types of accounts:
4//!
5//! - [Rewarder], which controls token rewards distribution
6//! - [Quarry], which receive rewards, and
7//! - [Miner], which stake tokens into [Quarry]s to receive rewards.
8//!
9//! This program is modeled after [Synthetix's StakingRewards.sol](https://github.com/Synthetixio/synthetix/blob/4b9b2ee09b38638de6fe1c38dbe4255a11ebed86/contracts/StakingRewards.sol).
10#![deny(rustdoc::all)]
11#![allow(rustdoc::missing_doc_code_examples)]
12#![allow(deprecated)]
13
14#[macro_use]
15mod macros;
16mod state;
17
18use anchor_lang::prelude::*;
19use anchor_spl::token::Token;
20use anchor_spl::token::{self, Mint, TokenAccount, Transfer};
21use payroll::Payroll;
22pub use state::*;
23use std::cmp;
24use vipers::prelude::*;
25
26pub mod account_validators;
27pub mod addresses;
28pub mod payroll;
29pub mod quarry;
30pub mod rewarder;
31
32mod instructions;
33pub use instructions::*;
34
35use crate::quarry::StakeAction;
36
37// declare_id!("QMNeHCGYnLVDn1icRAfQZpjPLBNkfGbSKRB83G5d8KB");
38declare_id!("9nj87mvFWstkzn56qYWDmBadr4v5fZRhkhkqgSKNRVQ5");
39
40/// Maximum number of tokens that can be rewarded by a [Rewarder] per year.
41pub const MAX_ANNUAL_REWARDS_RATE: u64 = u64::MAX >> 3;
42
43/// The fees of new [Rewarder]s: 1,000 milliBPS = 1 BP or 0.01%.
44/// This may be changed by governance in the future via program upgrade.
45pub const DEFAULT_CLAIM_FEE_MILLIBPS: u64 = 1_000;
46
47/// The maximum number of basis points possible.
48pub const MAX_BPS: u64 = 10_000;
49
50#[cfg(not(feature = "no-entrypoint"))]
51solana_security_txt::security_txt! {
52    name: "Quarry Mine",
53    project_url: "https://quarry.so",
54    contacts: "email:team@quarry.so",
55    policy: "https://github.com/QuarryProtocol/quarry/blob/master/SECURITY.md",
56
57    source_code: "https://github.com/QuarryProtocol/quarry",
58    auditors: "Quantstamp"
59}
60
61/// Program for [quarry_mine].
62#[program]
63pub mod quarry_mine {
64    use super::*;
65
66    // --------------------------------
67    // Rewarder Functions
68    // --------------------------------
69
70    /// Creates a new [Rewarder].
71    #[deprecated(since = "5.0.0", note = "Use `new_rewarder_v2` instead.")]
72    #[access_control(ctx.accounts.validate())]
73    pub fn new_rewarder(ctx: Context<NewRewarder>, _bump: u8) -> Result<()> {
74        instructions::new_rewarder::handler(ctx)
75    }
76
77    /// Creates a new [Rewarder].
78    ///
79    /// The V2 variant removes the need for supplying the bump and clock.
80    #[access_control(ctx.accounts.validate())]
81    pub fn new_rewarder_v2(ctx: Context<NewRewarderV2>) -> Result<()> {
82        instructions::new_rewarder_v2::handler(ctx)
83    }
84
85    /// Sets the pause authority.
86    #[access_control(ctx.accounts.validate())]
87    pub fn set_pause_authority(ctx: Context<SetPauseAuthority>) -> Result<()> {
88        let rewarder = &mut ctx.accounts.auth.rewarder;
89        rewarder.pause_authority = ctx.accounts.new_pause_authority.key();
90        Ok(())
91    }
92
93    /// Pauses the [Rewarder].
94    #[access_control(ctx.accounts.validate())]
95    pub fn pause(ctx: Context<MutableRewarderWithPauseAuthority>) -> Result<()> {
96        let rewarder = &mut ctx.accounts.rewarder;
97        rewarder.is_paused = true;
98        Ok(())
99    }
100
101    /// Unpauses the [Rewarder].
102    #[access_control(ctx.accounts.validate())]
103    pub fn unpause(ctx: Context<MutableRewarderWithPauseAuthority>) -> Result<()> {
104        let rewarder = &mut ctx.accounts.rewarder;
105        rewarder.is_paused = false;
106        Ok(())
107    }
108
109    /// Transfers the [Rewarder] authority to a different account.
110    #[access_control(ctx.accounts.validate())]
111    pub fn transfer_authority(
112        ctx: Context<TransferAuthority>,
113        new_authority: Pubkey,
114    ) -> Result<()> {
115        let rewarder = &mut ctx.accounts.rewarder;
116        rewarder.pending_authority = new_authority;
117        Ok(())
118    }
119
120    /// Accepts the authority to become the new rewarder.
121    #[access_control(ctx.accounts.validate())]
122    pub fn accept_authority(ctx: Context<AcceptAuthority>) -> Result<()> {
123        let rewarder = &mut ctx.accounts.rewarder;
124        let next_authority = rewarder.pending_authority;
125        rewarder.authority = next_authority;
126        rewarder.pending_authority = Pubkey::default();
127        Ok(())
128    }
129
130    /// Sets the amount of reward tokens distributed to all [Quarry]s per day.
131    #[access_control(ctx.accounts.validate())]
132    pub fn set_annual_rewards(ctx: Context<SetAnnualRewards>, new_rate: u64) -> Result<()> {
133        invariant!(
134            new_rate <= MAX_ANNUAL_REWARDS_RATE,
135            MaxAnnualRewardsRateExceeded
136        );
137        let rewarder = &mut ctx.accounts.auth.rewarder;
138        let previous_rate = rewarder.annual_rewards_rate;
139        rewarder.annual_rewards_rate = new_rate;
140
141        let current_ts = Clock::get()?.unix_timestamp;
142        emit!(RewarderAnnualRewardsUpdateEvent {
143            previous_rate,
144            new_rate,
145            timestamp: current_ts,
146        });
147
148        Ok(())
149    }
150
151    // --------------------------------
152    // Quarry functions
153    // --------------------------------
154
155    /// Creates a new [Quarry].
156    /// This may only be called by the [Rewarder]::authority.
157    #[deprecated(since = "5.0.0", note = "Use `create_quarry_v2` instead.")]
158    #[access_control(ctx.accounts.validate())]
159    pub fn create_quarry(ctx: Context<CreateQuarry>, _bump: u8) -> Result<()> {
160        instructions::create_quarry::handler(ctx)
161    }
162
163    /// Creates a new [Quarry].
164    /// This may only be called by the [Rewarder]::authority.
165    ///
166    /// The V2 variant removes the need for supplying the bump and clock.
167    #[access_control(ctx.accounts.validate())]
168    pub fn create_quarry_v2(ctx: Context<CreateQuarryV2>) -> Result<()> {
169        instructions::create_quarry_v2::handler(ctx)
170    }
171
172    /// Sets the rewards share of a quarry.
173    #[access_control(ctx.accounts.validate())]
174    pub fn set_rewards_share(ctx: Context<SetRewardsShare>, new_share: u64) -> Result<()> {
175        let rewarder = &mut ctx.accounts.auth.rewarder;
176        let quarry = &mut ctx.accounts.quarry;
177        rewarder.total_rewards_shares = unwrap_int!(rewarder
178            .total_rewards_shares
179            .checked_add(new_share)
180            .and_then(|v| v.checked_sub(quarry.rewards_share)));
181
182        let now = Clock::get()?.unix_timestamp;
183        quarry.last_update_ts = cmp::min(now, quarry.famine_ts);
184        quarry.annual_rewards_rate = rewarder.compute_quarry_annual_rewards_rate(new_share)?;
185        quarry.rewards_share = new_share;
186
187        emit!(QuarryRewardsUpdateEvent {
188            token_mint: quarry.token_mint_key,
189            annual_rewards_rate: quarry.annual_rewards_rate,
190            rewards_share: quarry.rewards_share,
191            timestamp: now,
192        });
193
194        Ok(())
195    }
196
197    /// Sets the famine, which stops rewards.
198    #[access_control(ctx.accounts.validate())]
199    pub fn set_famine(ctx: Context<SetFamine>, famine_ts: i64) -> Result<()> {
200        let quarry = &mut ctx.accounts.quarry;
201        quarry.famine_ts = famine_ts;
202
203        Ok(())
204    }
205
206    /// Synchronizes quarry rewards with the rewarder.
207    /// Anyone can call this.
208    #[access_control(ctx.accounts.validate())]
209    pub fn update_quarry_rewards(ctx: Context<UpdateQuarryRewards>) -> Result<()> {
210        let current_ts = Clock::get()?.unix_timestamp;
211        let rewarder = &ctx.accounts.rewarder;
212        let payroll: Payroll = (*ctx.accounts.quarry).into();
213        let quarry = &mut ctx.accounts.quarry;
214        quarry.update_rewards_internal(current_ts, rewarder, &payroll)?;
215
216        emit!(QuarryRewardsUpdateEvent {
217            token_mint: quarry.token_mint_key,
218            annual_rewards_rate: quarry.annual_rewards_rate,
219            rewards_share: quarry.rewards_share,
220            timestamp: current_ts,
221        });
222
223        Ok(())
224    }
225
226    /// --------------------------------
227    /// Miner functions
228    /// --------------------------------
229
230    /// Creates a [Miner] for the given authority.
231    ///
232    /// Anyone can call this; this is an associated account.
233    #[deprecated(since = "5.0.0", note = "Use `create_miner_v2` instead.")]
234    #[access_control(ctx.accounts.validate())]
235    pub fn create_miner(ctx: Context<CreateMiner>, _bump: u8) -> Result<()> {
236        instructions::create_miner::handler(ctx)
237    }
238
239    /// Creates a [Miner] for the given authority.
240    ///
241    /// Anyone can call this; this is an associated account.
242    ///
243    /// The V2 variant removes the need for supplying the bump.
244    #[access_control(ctx.accounts.validate())]
245    pub fn create_miner_v2(ctx: Context<CreateMiner>) -> Result<()> {
246        instructions::create_miner::handler(ctx)
247    }
248
249    /// Claims rewards for the [Miner].
250    #[deprecated(since = "5.0.0", note = "Use `claim_rewards_v2` instead.")]
251    #[access_control(ctx.accounts.validate())]
252    pub fn claim_rewards(ctx: Context<ClaimRewards>) -> Result<()> {
253        instructions::claim_rewards::handler(ctx)
254    }
255
256    /// Claims rewards for the [Miner].
257    ///
258    /// The V2 variant removes 2 accounts from the [crate::quarry_mine::claim_rewards] instruction.
259    #[access_control(ctx.accounts.validate())]
260    pub fn claim_rewards_v2(ctx: Context<ClaimRewardsV2>) -> Result<()> {
261        instructions::claim_rewards_v2::handler(ctx)
262    }
263
264    /// Stakes tokens into the [Miner].
265    #[access_control(ctx.accounts.validate())]
266    pub fn stake_tokens(ctx: Context<UserStake>, amount: u64) -> Result<()> {
267        if amount == 0 {
268            // noop
269            return Ok(());
270        }
271
272        let quarry = &mut ctx.accounts.quarry;
273        let clock = Clock::get()?;
274        quarry.process_stake_action_internal(
275            StakeAction::Stake,
276            clock.unix_timestamp,
277            &ctx.accounts.rewarder,
278            &mut ctx.accounts.miner,
279            amount,
280        )?;
281
282        let cpi_accounts = Transfer {
283            from: ctx.accounts.token_account.to_account_info(),
284            to: ctx.accounts.miner_vault.to_account_info(),
285            authority: ctx.accounts.authority.to_account_info(),
286        };
287        let cpi_program = ctx.accounts.token_program.to_account_info();
288        let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
289        // Transfer LP tokens to quarry vault
290        token::transfer(cpi_context, amount)?;
291
292        emit!(StakeEvent {
293            timestamp: clock.unix_timestamp,
294            authority: ctx.accounts.authority.key(),
295            amount,
296            token: ctx.accounts.token_account.mint,
297        });
298        Ok(())
299    }
300
301    /// Withdraws tokens from the [Miner].
302    #[access_control(ctx.accounts.validate())]
303    pub fn withdraw_tokens(ctx: Context<UserStake>, amount: u64) -> Result<()> {
304        if amount == 0 {
305            // noop
306            return Ok(());
307        }
308        invariant!(
309            amount <= ctx.accounts.miner_vault.amount,
310            InsufficientBalance
311        );
312
313        let clock = Clock::get()?;
314        let quarry = &mut ctx.accounts.quarry;
315        quarry.process_stake_action_internal(
316            StakeAction::Withdraw,
317            clock.unix_timestamp,
318            &ctx.accounts.rewarder,
319            &mut ctx.accounts.miner,
320            amount,
321        )?;
322
323        // Sign a transfer instruction as the [Miner]
324        let miner_seeds = &[
325            b"Miner".as_ref(),
326            ctx.accounts.miner.quarry.as_ref(),
327            ctx.accounts.miner.authority.as_ref(),
328            &[ctx.accounts.miner.bump],
329        ];
330        let signer_seeds = &[&miner_seeds[..]];
331        let cpi_accounts = token::Transfer {
332            from: ctx.accounts.miner_vault.to_account_info(),
333            to: ctx.accounts.token_account.to_account_info(),
334            authority: ctx.accounts.miner.to_account_info(),
335        };
336        let cpi_ctx = CpiContext::new_with_signer(
337            ctx.accounts.token_program.to_account_info(),
338            cpi_accounts,
339            signer_seeds,
340        );
341        // Transfer out LP tokens from quarry vault
342        token::transfer(cpi_ctx, amount)?;
343
344        emit!(WithdrawEvent {
345            timestamp: clock.unix_timestamp,
346            authority: ctx.accounts.authority.key(),
347            amount,
348            token: ctx.accounts.token_account.mint,
349        });
350        Ok(())
351    }
352
353    /// Withdraw tokens from a [Miner]-owned token account that is not the [Miner::token_vault_key].
354    /// This is useful for if tokens are sent directly to a [Miner].
355    ///
356    /// Only the [Miner::authority] may call this.
357    #[access_control(ctx.accounts.validate())]
358    pub fn rescue_tokens(ctx: Context<RescueTokens>) -> Result<()> {
359        instructions::rescue_tokens::handler(ctx)
360    }
361
362    // --------------------------------
363    // Protocol Functions
364    // --------------------------------
365
366    /// Extracts fees to the Quarry DAO.
367    /// This can be called by anyone.
368    #[access_control(ctx.accounts.validate())]
369    pub fn extract_fees(ctx: Context<ExtractFees>) -> Result<()> {
370        let seeds = gen_rewarder_signer_seeds!(ctx.accounts.rewarder);
371        let signer_seeds = &[&seeds[..]];
372
373        // Transfer the tokens to the DAO address.
374        token::transfer(
375            CpiContext::new_with_signer(
376                ctx.accounts.token_program.to_account_info(),
377                token::Transfer {
378                    from: ctx.accounts.claim_fee_token_account.to_account_info(),
379                    to: ctx.accounts.fee_to_token_account.to_account_info(),
380                    authority: ctx.accounts.rewarder.to_account_info(),
381                },
382                signer_seeds,
383            ),
384            ctx.accounts.claim_fee_token_account.amount,
385        )?;
386
387        Ok(())
388    }
389}
390
391/// --------------------------------
392/// Context Structs
393/// --------------------------------
394
395/* Rewarder contexts */
396
397/// Accounts for [quarry_mine::set_pause_authority].
398#[derive(Accounts)]
399pub struct SetPauseAuthority<'info> {
400    /// [Rewarder].
401    pub auth: MutableRewarderWithAuthority<'info>,
402
403    /// The pause authority.
404    /// CHECK: OK
405    pub new_pause_authority: UncheckedAccount<'info>,
406}
407
408/// Accounts for [quarry_mine::transfer_authority].
409#[derive(Accounts)]
410pub struct TransferAuthority<'info> {
411    /// Authority of the rewarder.
412    pub authority: Signer<'info>,
413
414    /// Rewarder of the farm.
415    #[account(mut)]
416    pub rewarder: Account<'info, Rewarder>,
417}
418
419/// Accounts for [quarry_mine::accept_authority].
420#[derive(Accounts)]
421pub struct AcceptAuthority<'info> {
422    /// Authority of the next rewarder.
423    pub authority: Signer<'info>,
424
425    /// Rewarder of the farm.
426    #[account(mut)]
427    pub rewarder: Account<'info, Rewarder>,
428}
429
430/// Mutable [Rewarder] that requires the authority to be a signer.
431#[derive(Accounts, Clone)]
432pub struct MutableRewarderWithAuthority<'info> {
433    /// Authority of the rewarder.
434    pub authority: Signer<'info>,
435
436    /// Rewarder of the farm.
437    #[account(mut, has_one = authority @ ErrorCode::Unauthorized)]
438    pub rewarder: Account<'info, Rewarder>,
439}
440
441/// Read-only [Rewarder] that requires the authority to be a signer.
442#[derive(Accounts)]
443pub struct ReadOnlyRewarderWithAuthority<'info> {
444    /// Authority of the rewarder.
445    pub authority: Signer<'info>,
446
447    /// [Rewarder].
448    #[account(has_one = authority)]
449    pub rewarder: Account<'info, Rewarder>,
450}
451
452/// Accounts for [quarry_mine::set_annual_rewards].
453#[derive(Accounts)]
454pub struct SetAnnualRewards<'info> {
455    /// [Rewarder],
456    pub auth: MutableRewarderWithAuthority<'info>,
457}
458
459/* Quarry contexts */
460
461/// Accounts for [quarry_mine::set_famine].
462#[derive(Accounts)]
463pub struct SetFamine<'info> {
464    /// [Rewarder] of the [Quarry].
465    pub auth: ReadOnlyRewarderWithAuthority<'info>,
466
467    /// [Quarry] updated.
468    #[account(mut, constraint = quarry.rewarder == auth.rewarder.key())]
469    pub quarry: Account<'info, Quarry>,
470}
471
472/// Accounts for [quarry_mine::set_rewards_share].
473#[derive(Accounts)]
474pub struct SetRewardsShare<'info> {
475    /// [Rewarder] of the [Quarry].
476    pub auth: MutableRewarderWithAuthority<'info>,
477
478    /// [Quarry] updated.
479    #[account(mut)]
480    pub quarry: Account<'info, Quarry>,
481}
482
483/// Accounts for [quarry_mine::update_quarry_rewards].
484#[derive(Accounts)]
485pub struct UpdateQuarryRewards<'info> {
486    /// [Quarry].
487    #[account(mut)]
488    pub quarry: Account<'info, Quarry>,
489
490    /// [Rewarder].
491    pub rewarder: Account<'info, Rewarder>,
492}
493
494/* Miner contexts */
495
496/// Staking accounts
497///
498/// This accounts struct is always used in the context of the user authority
499/// staking into an account. This is NEVER used by an admin.
500///
501/// Validation should be extremely conservative.
502#[derive(Accounts, Clone)]
503pub struct UserStake<'info> {
504    /// Miner authority (i.e. the user).
505    pub authority: Signer<'info>,
506
507    /// Miner.
508    #[account(mut)]
509    pub miner: Account<'info, Miner>,
510
511    /// Quarry to claim from.
512    #[account(mut)]
513    pub quarry: Account<'info, Quarry>,
514
515    /// Vault of the miner.
516    #[account(mut)]
517    pub miner_vault: Account<'info, TokenAccount>,
518
519    /// User's staked token account
520    #[account(mut)]
521    pub token_account: Account<'info, TokenAccount>,
522
523    /// Token program
524    pub token_program: Program<'info, Token>,
525
526    /// Rewarder
527    pub rewarder: Account<'info, Rewarder>,
528}
529
530/// Accounts for [quarry_mine::extract_fees].
531#[derive(Accounts)]
532pub struct ExtractFees<'info> {
533    /// Rewarder to extract fees from.
534    #[account(has_one = claim_fee_token_account)]
535    pub rewarder: Account<'info, Rewarder>,
536
537    /// [TokenAccount] which receives claim fees.
538    #[account(mut)]
539    pub claim_fee_token_account: Account<'info, TokenAccount>,
540
541    /// [TokenAccount] owned by the [addresses::FEE_TO].
542    /// Holds DAO claim fees.
543    #[account(mut)]
544    pub fee_to_token_account: Account<'info, TokenAccount>,
545
546    /// Token program
547    pub token_program: Program<'info, Token>,
548}
549
550/// Accounts for [quarry_mine::pause] and [quarry_mine::unpause].
551#[derive(Accounts)]
552pub struct MutableRewarderWithPauseAuthority<'info> {
553    /// Pause authority of the rewarder.
554    pub pause_authority: Signer<'info>,
555
556    /// Rewarder of the farm.
557    #[account(mut)]
558    pub rewarder: Account<'info, Rewarder>,
559}
560
561// --------------------------------
562// Events
563// --------------------------------
564
565/// Emitted when tokens are staked into a [Quarry].
566#[event]
567pub struct StakeEvent {
568    /// Authority staking.
569    #[index]
570    pub authority: Pubkey,
571    /// Mint of token staked.
572    #[index]
573    pub token: Pubkey,
574    /// Amount staked.
575    pub amount: u64,
576    /// When the event took place.
577    pub timestamp: i64,
578}
579
580/// Emitted when tokens are withdrawn from a [Quarry].
581#[event]
582pub struct WithdrawEvent {
583    /// Authority withdrawing.
584    #[index]
585    pub authority: Pubkey,
586    /// Mint of token withdrawn.
587    #[index]
588    pub token: Pubkey,
589    /// Amount withdrawn.
590    pub amount: u64,
591    /// When the event took place.
592    pub timestamp: i64,
593}
594
595/// Emitted when the daily rewards rate is updated.
596#[event]
597pub struct RewarderAnnualRewardsUpdateEvent {
598    /// Previous rate of rewards.
599    pub previous_rate: u64,
600    /// New rate of rewards.
601    pub new_rate: u64,
602    /// When the event took place.
603    pub timestamp: i64,
604}
605
606/// Emitted when a quarry's reward share is updated.
607#[event]
608pub struct QuarryRewardsUpdateEvent {
609    /// [Mint] of the [Quarry] token.
610    pub token_mint: Pubkey,
611    /// New annual rewards rate
612    pub annual_rewards_rate: u64,
613    /// New rewards share.
614    pub rewards_share: u64,
615    /// When the event took place.
616    pub timestamp: i64,
617}
618
619/// Error Codes
620#[error_code]
621pub enum ErrorCode {
622    #[msg("You are not authorized to perform this action.")]
623    Unauthorized,
624    #[msg("Insufficient staked balance for withdraw request.")]
625    InsufficientBalance,
626    #[msg("Pending authority not set")]
627    PendingAuthorityNotSet,
628    #[msg("Invalid quarry rewards share")]
629    InvalidRewardsShare,
630    #[msg("Insufficient allowance.")]
631    InsufficientAllowance,
632    #[msg("New vault not empty.")]
633    NewVaultNotEmpty,
634    #[msg("Not enough tokens.")]
635    NotEnoughTokens,
636    #[msg("Invalid timestamp.")]
637    InvalidTimestamp,
638    #[msg("Invalid max claim fee.")]
639    InvalidMaxClaimFee,
640    #[msg("Max annual rewards rate exceeded.")]
641    MaxAnnualRewardsRateExceeded,
642    #[msg("Rewarder is paused.")]
643    Paused,
644    #[msg("Rewards earned exceeded quarry's upper bound.")]
645    UpperboundExceeded,
646}