testsvm_quarry/
test_quarry.rs

1//! # Quarry Testing Utilities
2//!
3//! Test helpers for individual quarries in the Quarry protocol.
4//!
5//! This module provides the `TestQuarry` struct for managing individual quarry
6//! instances within the Quarry mining system. Each quarry represents a staking
7//! pool where users can deposit tokens to earn rewards based on their share of
8//! the total staked amount.
9//!
10//! ## Features
11//!
12//! - **Miner Creation**: Create and manage individual miners within a quarry
13//! - **Staking Operations**: Handle token deposits and withdrawals
14//! - **Reward Distribution**: Track and claim mining rewards
15//! - **Account Management**: Type-safe references to all quarry accounts
16
17use crate::{TestRewarder, quarry_mine, quarry_mint_wrapper};
18use anyhow::Result;
19use solana_sdk::pubkey::Pubkey;
20use solana_sdk::signature::{Keypair, Signer};
21use std::fmt;
22use testsvm::prelude::*;
23
24/// Test quarry with labeled accounts
25#[derive(Debug)]
26pub struct TestQuarry {
27    pub label: String,
28    pub quarry: AccountRef<quarry_mine::accounts::Quarry>,
29    pub rewarder: Pubkey,
30    pub staked_token_mint: AccountRef<anchor_spl::token::Mint>,
31}
32
33impl TestQuarry {
34    /// Fetch the Quarry account from chain
35    pub fn fetch_quarry(&self, env: &TestSVM) -> Result<quarry_mine::accounts::Quarry> {
36        self.quarry.load(env)
37    }
38
39    /// Create a miner for a user
40    pub fn create_miner(
41        &self,
42        env: &mut TestSVM,
43        label: &str,
44        user: &Keypair,
45    ) -> Result<(
46        AccountRef<quarry_mine::accounts::Miner>,
47        AccountRef<anchor_spl::token::TokenAccount>,
48    )> {
49        let miner = env.get_pda(
50            &format!("miner_{label}"),
51            &[b"Miner", self.quarry.key.as_ref(), user.pubkey().as_ref()],
52            quarry_mine::ID,
53        )?;
54
55        // Create the miner vault ATA first
56        let (create_vault_ix, miner_vault) = env.create_ata_ix(
57            &format!("miner_vault_{label}"),
58            &miner.key,
59            &self.staked_token_mint.key,
60        )?;
61        env.execute_ixs(&[create_vault_ix])?;
62
63        let create_miner_ix = anchor_instruction(
64            quarry_mine::ID,
65            quarry_mine::client::accounts::CreateMinerV2 {
66                quarry: self.quarry.key,
67                rewarder: self.rewarder,
68                miner: miner.key,
69                authority: user.pubkey(),
70                payer: env.default_fee_payer(),
71                token_mint: self.staked_token_mint.key,
72                miner_vault: miner_vault.key,
73                system_program: solana_sdk::system_program::ID,
74                token_program: anchor_spl::token::ID,
75            },
76            quarry_mine::client::args::CreateMinerV2 {},
77        );
78
79        env.execute_ixs_with_signers(&[create_miner_ix], &[user])?;
80
81        Ok((miner, miner_vault))
82    }
83
84    /// Stake tokens into the miner
85    pub fn stake_tokens(
86        &self,
87        env: &mut TestSVM,
88        miner: &AccountRef<quarry_mine::accounts::Miner>,
89        miner_vault: &AccountRef<anchor_spl::token::TokenAccount>,
90        user_token_account: &AccountRef<anchor_spl::token::TokenAccount>,
91        amount: u64,
92        user: &Keypair,
93    ) -> Result<()> {
94        let stake_ix = anchor_instruction(
95            quarry_mine::ID,
96            quarry_mine::client::accounts::StakeTokens {
97                authority: user.pubkey(),
98                miner: miner.key,
99                quarry: self.quarry.key,
100                rewarder: self.rewarder,
101                token_account: user_token_account.key,
102                miner_vault: miner_vault.key,
103                token_program: anchor_spl::token::ID,
104            },
105            quarry_mine::client::args::StakeTokens { amount },
106        );
107
108        env.execute_ixs_with_signers(&[stake_ix], &[user])?;
109
110        Ok(())
111    }
112
113    /// Update quarry rewards to reflect time passage
114    pub fn update_quarry_rewards(&self, env: &mut TestSVM) -> Result<()> {
115        let update_ix = anchor_instruction(
116            quarry_mine::ID,
117            quarry_mine::client::accounts::UpdateQuarryRewards {
118                quarry: self.quarry.key,
119                rewarder: self.rewarder,
120            },
121            quarry_mine::client::args::UpdateQuarryRewards {},
122        );
123
124        env.execute_ixs(&[update_ix])?;
125
126        Ok(())
127    }
128
129    /// Withdraw tokens from the miner
130    pub fn withdraw_tokens(
131        &self,
132        env: &mut TestSVM,
133        miner: &AccountRef<quarry_mine::accounts::Miner>,
134        miner_vault: &AccountRef<anchor_spl::token::TokenAccount>,
135        user_token_account: &AccountRef<anchor_spl::token::TokenAccount>,
136        amount: u64,
137        user: &Keypair,
138    ) -> Result<()> {
139        let withdraw_ix = anchor_instruction(
140            quarry_mine::ID,
141            quarry_mine::client::accounts::WithdrawTokens {
142                authority: user.pubkey(),
143                miner: miner.key,
144                quarry: self.quarry.key,
145                rewarder: self.rewarder,
146                token_account: user_token_account.key,
147                miner_vault: miner_vault.key,
148                token_program: anchor_spl::token::ID,
149            },
150            quarry_mine::client::args::WithdrawTokens { amount },
151        );
152
153        env.execute_ixs_with_signers(&[withdraw_ix], &[user])?;
154
155        Ok(())
156    }
157
158    /// Claim rewards for a miner
159    pub fn claim_rewards(
160        &self,
161        env: &mut TestSVM,
162        rewarder: &TestRewarder,
163        miner: &AccountRef<quarry_mine::accounts::Miner>,
164        _miner_vault: &AccountRef<anchor_spl::token::TokenAccount>,
165        user_rewards_account: &AccountRef<anchor_spl::token::TokenAccount>,
166        user: &Keypair,
167    ) -> Result<()> {
168        // Find the minter PDA - it should already exist from perform_new_minter
169        let (minter, _) = Pubkey::find_program_address(
170            &[
171                b"MintWrapperMinter",
172                rewarder.mint_wrapper.mint_wrapper.key.as_ref(),
173                rewarder.rewarder.key.as_ref(),
174            ],
175            &quarry_mint_wrapper::ID,
176        );
177
178        let claim_ix = anchor_instruction(
179            quarry_mine::ID,
180            quarry_mine::client::accounts::ClaimRewardsV2 {
181                mint_wrapper: rewarder.mint_wrapper.mint_wrapper.key,
182                mint_wrapper_program: quarry_mint_wrapper::ID,
183                minter,
184                rewards_token_mint: rewarder.mint_wrapper.reward_token_mint.key,
185                rewards_token_account: user_rewards_account.key,
186                claim_fee_token_account: rewarder.claim_fee_token_account.key,
187                claim: quarry_mine::client::accounts::Claim {
188                    authority: user.pubkey(),
189                    miner: miner.key,
190                    quarry: self.quarry.key,
191                    token_program: anchor_spl::token::ID,
192                    rewarder: self.rewarder,
193                },
194            },
195            quarry_mine::client::args::ClaimRewardsV2 {},
196        );
197
198        env.execute_ixs_with_signers(&[claim_ix], &[user])?;
199
200        Ok(())
201    }
202}
203
204impl fmt::Display for TestQuarry {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        write!(f, "{}", self.quarry.key)
207    }
208}
209
210impl AsRef<[u8]> for TestQuarry {
211    fn as_ref(&self) -> &[u8] {
212        self.quarry.key.as_ref()
213    }
214}