1#![deny(rustdoc::all)]
3#![allow(rustdoc::missing_doc_code_examples)]
4#![allow(deprecated)]
5
6#[macro_use]
7mod macros;
8
9mod account_validators;
10mod processor;
11use processor::*;
12
13pub(crate) mod account_conversions;
14pub(crate) mod mm_cpi;
15
16pub mod events;
17pub mod state;
18
19use anchor_lang::prelude::*;
20use anchor_spl::token::{Mint, Token, TokenAccount};
21use vipers::prelude::*;
22
23pub use state::*;
24
25#[cfg(not(feature = "no-entrypoint"))]
26solana_security_txt::security_txt! {
27 name: "Quarry Merge Mine",
28 project_url: "https://quarry.so",
29 contacts: "email:team@quarry.so",
30 policy: "https://github.com/QuarryProtocol/quarry/blob/master/SECURITY.md",
31
32 source_code: "https://github.com/QuarryProtocol/quarry",
33 auditors: "Quantstamp"
34}
35
36declare_id!("QMMD16kjauP5knBwxNUJRZ1Z5o3deBuFrqVjBVmmqto");
37
38#[deny(clippy::integer_arithmetic, clippy::float_arithmetic)]
39#[program]
40pub mod quarry_merge_mine {
42 use super::*;
43
44 #[deprecated(since = "5.0.0", note = "Use `new_pool_v2` instead.")]
47 #[access_control(ctx.accounts.validate())]
48 pub fn new_pool(ctx: Context<NewPool>, _bump: u8, _mint_bump: u8) -> Result<()> {
49 processor::init::new_pool(ctx)
50 }
51
52 #[access_control(ctx.accounts.validate())]
57 pub fn new_pool_v2(ctx: Context<NewPool>) -> Result<()> {
58 processor::init::new_pool(ctx)
59 }
60
61 #[deprecated(since = "5.0.0", note = "Use `init_merge_miner_v2` instead.")]
64 #[access_control(ctx.accounts.validate())]
65 pub fn init_merge_miner(ctx: Context<InitMergeMiner>, _bump: u8) -> Result<()> {
66 processor::init::init_merge_miner(ctx)
67 }
68
69 #[access_control(ctx.accounts.validate())]
74 pub fn init_merge_miner_v2(ctx: Context<InitMergeMiner>) -> Result<()> {
75 processor::init::init_merge_miner(ctx)
76 }
77
78 #[deprecated(since = "5.0.0", note = "Use `init_miner_v2` instead.")]
80 #[access_control(ctx.accounts.validate())]
81 pub fn init_miner(ctx: Context<InitMiner>, _bump: u8) -> Result<()> {
82 processor::init::init_miner(ctx)
83 }
84
85 #[access_control(ctx.accounts.validate())]
87 pub fn init_miner_v2(ctx: Context<InitMiner>) -> Result<()> {
88 processor::init::init_miner(ctx)
89 }
90
91 #[access_control(ctx.accounts.validate())]
99 pub fn stake_primary_miner(ctx: Context<QuarryStakePrimary>) -> Result<()> {
100 processor::deposit::stake_primary_miner(ctx)
101 }
102
103 #[access_control(ctx.accounts.validate())]
107 pub fn stake_replica_miner(ctx: Context<QuarryStakeReplica>) -> Result<()> {
108 processor::deposit::stake_replica_miner(ctx)
109 }
110
111 #[access_control(ctx.accounts.validate())]
117 pub fn unstake_primary_miner(ctx: Context<QuarryStakePrimary>, amount: u64) -> Result<()> {
118 processor::withdraw::unstake_primary_miner(ctx, amount)
119 }
120
121 #[access_control(ctx.accounts.validate())]
123 pub fn unstake_all_replica_miner(ctx: Context<QuarryStakeReplica>) -> Result<()> {
124 processor::withdraw::unstake_all_replica_miner(ctx)
125 }
126
127 #[access_control(ctx.accounts.validate())]
129 pub fn withdraw_tokens(ctx: Context<WithdrawTokens>) -> Result<()> {
130 processor::withdraw::withdraw_tokens(ctx)
131 }
132
133 #[access_control(ctx.accounts.validate())]
135 pub fn rescue_tokens(ctx: Context<RescueTokens>) -> Result<()> {
136 processor::rescue_tokens::handler(ctx)
137 }
138
139 #[access_control(ctx.accounts.validate())]
145 pub fn claim_rewards(ctx: Context<ClaimRewards>) -> Result<()> {
146 processor::claim::claim_rewards(ctx)
147 }
148}
149
150#[derive(Accounts)]
156pub struct NewPool<'info> {
157 #[account(
159 init,
160 seeds = [
161 b"MergePool".as_ref(),
162 primary_mint.key().to_bytes().as_ref()
163 ],
164 bump,
165 payer = payer,
166 space = 8 + MergePool::LEN
167 )]
168 pub pool: Account<'info, MergePool>,
169
170 pub primary_mint: Account<'info, Mint>,
172
173 #[account(
175 init,
176 seeds = [
177 b"ReplicaMint".as_ref(),
178 pool.key().to_bytes().as_ref()
179 ],
180 mint::decimals = primary_mint.decimals,
181 mint::authority = pool,
182 bump,
183 payer = payer
184 )]
185 pub replica_mint: Account<'info, Mint>,
186
187 #[account(mut)]
189 pub payer: Signer<'info>,
190
191 pub token_program: Program<'info, Token>,
193
194 pub system_program: Program<'info, System>,
196
197 pub rent: Sysvar<'info, Rent>,
199}
200
201#[derive(Accounts)]
203pub struct InitMergeMiner<'info> {
204 pub pool: Account<'info, MergePool>,
206
207 pub owner: UncheckedAccount<'info>,
210
211 #[account(
213 init,
214 seeds = [
215 b"MergeMiner".as_ref(),
216 pool.key().to_bytes().as_ref(),
217 owner.key().to_bytes().as_ref()
218 ],
219 bump,
220 payer = payer,
221 space = 8 + MergeMiner::LEN
222 )]
223 pub mm: Account<'info, MergeMiner>,
224
225 #[account(mut)]
227 pub payer: Signer<'info>,
228
229 pub system_program: Program<'info, System>,
231}
232
233#[derive(Accounts)]
235pub struct InitMiner<'info> {
236 pub pool: Account<'info, MergePool>,
238
239 pub mm: Account<'info, MergeMiner>,
241
242 #[account(mut)]
244 pub miner: SystemAccount<'info>,
245
246 #[account(mut)]
248 pub quarry: Box<Account<'info, quarry_mine::Quarry>>,
249
250 pub rewarder: Box<Account<'info, quarry_mine::Rewarder>>,
252
253 pub token_mint: Box<Account<'info, Mint>>,
255
256 pub miner_vault: Account<'info, TokenAccount>,
258
259 #[account(mut)]
261 pub payer: Signer<'info>,
262
263 pub mine_program: Program<'info, quarry_mine::program::QuarryMine>,
265
266 pub system_program: Program<'info, System>,
268
269 pub token_program: Program<'info, Token>,
271}
272
273#[derive(Accounts)]
275pub struct WithdrawTokens<'info> {
276 pub owner: Signer<'info>,
278 pub pool: Account<'info, MergePool>,
280 #[account(mut)]
282 pub mm: Account<'info, MergeMiner>,
283
284 pub withdraw_mint: Account<'info, Mint>,
286 #[account(mut)]
289 pub mm_token_account: Account<'info, TokenAccount>,
290 #[account(mut)]
292 pub token_destination: Account<'info, TokenAccount>,
293
294 pub token_program: Program<'info, Token>,
296}
297
298#[derive(Accounts)]
300pub struct ClaimRewards<'info> {
301 #[account(mut)]
303 pub mint_wrapper: Box<Account<'info, quarry_mint_wrapper::MintWrapper>>,
304 pub mint_wrapper_program: Program<'info, quarry_mint_wrapper::program::QuarryMintWrapper>,
306 #[account(mut)]
308 pub minter: Box<Account<'info, quarry_mint_wrapper::Minter>>,
309
310 #[account(mut)]
312 pub rewards_token_mint: Box<Account<'info, Mint>>,
313
314 #[account(mut)]
316 pub rewards_token_account: Box<Account<'info, TokenAccount>>,
317
318 #[account(mut)]
320 pub claim_fee_token_account: Box<Account<'info, TokenAccount>>,
321
322 #[account(mut)]
325 pub stake_token_account: Box<Account<'info, TokenAccount>>,
326
327 pub stake: QuarryStake<'info>,
329}
330
331#[derive(Accounts)]
333pub struct QuarryStakePrimary<'info> {
334 #[account(constraint = mm_owner.key() == stake.mm.owner)]
336 pub mm_owner: Signer<'info>,
337
338 #[account(mut)]
340 pub mm_primary_token_account: Account<'info, TokenAccount>,
341
342 pub stake: QuarryStake<'info>,
344}
345
346#[derive(Accounts)]
348pub struct QuarryStakeReplica<'info> {
349 #[account(constraint = mm_owner.key() == stake.mm.owner)]
351 pub mm_owner: Signer<'info>,
352
353 #[account(mut)]
357 pub replica_mint: Account<'info, Mint>,
358
359 #[account(mut)]
361 pub replica_mint_token_account: Account<'info, TokenAccount>,
362
363 pub stake: QuarryStake<'info>,
365}
366
367#[derive(Accounts)]
373pub struct QuarryStake<'info> {
374 #[account(mut)]
376 pub pool: Account<'info, MergePool>,
377
378 #[account(mut, has_one = pool)]
380 pub mm: Account<'info, MergeMiner>,
381
382 pub rewarder: Box<Account<'info, quarry_mine::Rewarder>>,
384
385 #[account(mut, has_one = rewarder)]
387 pub quarry: Box<Account<'info, quarry_mine::Quarry>>,
388
389 #[account(
391 mut,
392 has_one = quarry,
393 constraint = miner.authority == mm.key()
394 )]
395 pub miner: Box<Account<'info, quarry_mine::Miner>>,
396
397 #[account(mut, constraint = miner_vault.key() == miner.token_vault_key)]
399 pub miner_vault: Account<'info, TokenAccount>,
400
401 pub token_program: Program<'info, Token>,
403
404 pub mine_program: Program<'info, quarry_mine::program::QuarryMine>,
406}
407
408#[error_code]
410pub enum ErrorCode {
411 #[msg("Unauthorized.")]
412 Unauthorized,
413 #[msg("Insufficient balance.")]
414 InsufficientBalance,
415 #[msg("Invalid miner for the given quarry.")]
416 InvalidMiner,
417 #[msg("Cannot withdraw a replica mint.")]
418 CannotWithdrawReplicaMint,
419 #[msg("User must first withdraw from all replica quarries.")]
420 OutstandingReplicaTokens,
421 #[msg("The replica mint must have the same number of decimals as the primary mint.")]
422 ReplicaDecimalsMismatch,
423 #[msg("The replica mint must have zero supply.")]
424 ReplicaNonZeroSupply,
425}