shadow_drive_sdk/client/
claim_stake.rs

1use anchor_lang::{system_program, InstructionData, ToAccountMetas};
2use shadow_drive_user_staking::accounts as shdw_drive_accounts;
3use shadow_drive_user_staking::instruction as shdw_drive_instructions;
4use solana_sdk::{
5    instruction::Instruction, pubkey::Pubkey, signer::Signer, transaction::Transaction,
6};
7use spl_associated_token_account::get_associated_token_address;
8
9use super::ShadowDriveClient;
10use crate::{
11    constants::{PROGRAM_ADDRESS, STORAGE_CONFIG_PDA, TOKEN_MINT},
12    derived_addresses::*,
13    models::{
14        storage_acct::{StorageAccount, StorageAccountV2, StorageAcct},
15        *,
16    },
17};
18use spl_token::ID as TokenProgramID;
19
20impl<T> ShadowDriveClient<T>
21where
22    T: Signer,
23{
24    /// Claims any available stake as a result of the `reduce_storage` command.
25    /// After reducing storage amount, users must wait until the end of the epoch to successfully claim their stake.
26    /// * `storage_account_key` - The public key of the [`StorageAccount`](crate::models::StorageAccount) that you want to claim excess stake from.
27    /// # Example
28    ///
29    /// ```
30    /// # use shadow_drive_rust::{ShadowDriveClient, derived_addresses::storage_account};
31    /// # use solana_client::rpc_client::RpcClient;
32    /// # use solana_sdk::{
33    /// # pubkey::Pubkey,
34    /// # signature::Keypair,
35    /// # signer::{keypair::read_keypair_file, Signer},
36    /// # };
37    /// #
38    /// # let keypair = read_keypair_file(KEYPAIR_PATH).expect("failed to load keypair at path");
39    /// # let user_pubkey = keypair.pubkey();
40    /// # let rpc_client = RpcClient::new("https://ssc-dao.genesysgo.net");
41    /// # let shdw_drive_client = ShadowDriveClient::new(keypair, rpc_client);
42    /// # let (storage_account_key, _) = storage_account(&user_pubkey, 0);
43    /// #
44    /// let claim_stake = shdw_drive_client
45    ///     .claim_stake(&storage_account_key)
46    ///     .await?;
47    /// ```
48    pub async fn claim_stake(
49        &self,
50        storage_account_key: &Pubkey,
51    ) -> ShadowDriveResult<ShdwDriveResponse> {
52        let selected_account = self.get_storage_account(storage_account_key).await?;
53
54        let txn = match selected_account {
55            StorageAcct::V1(storage_account) => {
56                self.claim_stake_v1(storage_account_key, storage_account)
57                    .await?
58            }
59            StorageAcct::V2(storage_account) => {
60                self.claim_stake_v2(storage_account_key, storage_account)
61                    .await?
62            }
63        };
64
65        let txn_result = self.rpc_client.send_and_confirm_transaction(&txn).await?;
66
67        Ok(ShdwDriveResponse {
68            txid: txn_result.to_string(),
69        })
70    }
71
72    async fn claim_stake_v1(
73        &self,
74        storage_account_key: &Pubkey,
75        storage_account: StorageAccount,
76    ) -> ShadowDriveResult<Transaction> {
77        let wallet_pubkey = self.wallet.pubkey();
78        let unstake_account = unstake_account(storage_account_key).0;
79        let unstake_info_account = unstake_info(storage_account_key).0;
80        let owner_ata = get_associated_token_address(&wallet_pubkey, &TOKEN_MINT);
81
82        let accounts = shdw_drive_accounts::ClaimStakeV1 {
83            storage_config: *STORAGE_CONFIG_PDA,
84            storage_account: *storage_account_key,
85            unstake_info: unstake_info_account,
86            unstake_account,
87            owner: storage_account.owner_1,
88            owner_ata,
89            token_mint: TOKEN_MINT,
90            system_program: system_program::ID,
91            token_program: TokenProgramID,
92        };
93
94        let args = shdw_drive_instructions::ClaimStake {};
95
96        let instruction = Instruction {
97            program_id: PROGRAM_ADDRESS,
98            accounts: accounts.to_account_metas(None),
99            data: args.data(),
100        };
101
102        let txn = Transaction::new_signed_with_payer(
103            &[instruction],
104            Some(&wallet_pubkey),
105            &[&self.wallet],
106            self.rpc_client.get_latest_blockhash().await?,
107        );
108
109        Ok(txn)
110    }
111
112    async fn claim_stake_v2(
113        &self,
114        storage_account_key: &Pubkey,
115        storage_account: StorageAccountV2,
116    ) -> ShadowDriveResult<Transaction> {
117        let wallet_pubkey = self.wallet.pubkey();
118        let unstake_account = unstake_account(storage_account_key).0;
119        let unstake_info_account = unstake_info(storage_account_key).0;
120        let owner_ata = get_associated_token_address(&wallet_pubkey, &TOKEN_MINT);
121
122        let accounts = shdw_drive_accounts::ClaimStakeV2 {
123            storage_config: *STORAGE_CONFIG_PDA,
124            storage_account: *storage_account_key,
125            unstake_info: unstake_info_account,
126            unstake_account,
127            owner: storage_account.owner_1,
128            owner_ata,
129            token_mint: TOKEN_MINT,
130            system_program: system_program::ID,
131            token_program: TokenProgramID,
132        };
133
134        let args = shdw_drive_instructions::ClaimStake2 {};
135
136        let instruction = Instruction {
137            program_id: PROGRAM_ADDRESS,
138            accounts: accounts.to_account_metas(None),
139            data: args.data(),
140        };
141
142        let txn = Transaction::new_signed_with_payer(
143            &[instruction],
144            Some(&wallet_pubkey),
145            &[&self.wallet],
146            self.rpc_client.get_latest_blockhash().await?,
147        );
148
149        Ok(txn)
150    }
151}