shadow_drive_sdk/client/
add_immutable_storage.rs1use anchor_lang::{system_program, InstructionData, ToAccountMetas};
2use byte_unit::Byte;
3use shadow_drive_user_staking::accounts as shdw_drive_accounts;
4use shadow_drive_user_staking::instruction as shdw_drive_instructions;
5
6use solana_sdk::{
7    instruction::Instruction, pubkey::Pubkey, signer::Signer, transaction::Transaction,
8};
9use spl_associated_token_account::get_associated_token_address;
10use spl_token::ID as TokenProgramID;
11
12use super::ShadowDriveClient;
13use crate::models::storage_acct::{StorageAccount, StorageAccountV2, StorageAcct};
14use crate::serialize_and_encode;
15use crate::{
16    constants::{EMISSIONS, PROGRAM_ADDRESS, STORAGE_CONFIG_PDA, TOKEN_MINT, UPLOADER},
17    error::Error,
18    models::*,
19};
20
21impl<T> ShadowDriveClient<T>
22where
23    T: Signer,
24{
25    pub async fn add_immutable_storage(
54        &self,
55        storage_account_key: &Pubkey,
56        size: Byte,
57    ) -> ShadowDriveResult<StorageResponse> {
58        let size_as_bytes: u64 = size
59            .get_bytes()
60            .try_into()
61            .map_err(|_| Error::InvalidStorage)?;
62
63        let selected_storage_acct = self.get_storage_account(storage_account_key).await?;
64
65        let txn_encoded = match selected_storage_acct {
66            StorageAcct::V1(storage_account) => {
67                if !storage_account.immutable {
68                    return Err(Error::StorageAccountIsNotImmutable);
69                }
70                self.add_immutable_storage_v1(storage_account_key, storage_account, size_as_bytes)
71                    .await?
72            }
73            StorageAcct::V2(storage_account) => {
74                if !storage_account.immutable {
75                    return Err(Error::StorageAccountIsNotImmutable);
76                }
77                self.add_immutable_storage_v2(storage_account_key, storage_account, size_as_bytes)
78                    .await?
79            }
80        };
81
82        self.send_shdw_txn("add-storage", txn_encoded, None).await
83    }
84
85    async fn add_immutable_storage_v1(
86        &self,
87        storage_account_key: &Pubkey,
88        storage_account: StorageAccount,
89        size_as_bytes: u64,
90    ) -> ShadowDriveResult<String> {
91        let wallet_pubkey = &self.wallet.pubkey();
92        let owner_ata = get_associated_token_address(wallet_pubkey, &TOKEN_MINT);
93        let emissions_ata = get_associated_token_address(&EMISSIONS, &TOKEN_MINT);
94
95        let accounts = shdw_drive_accounts::IncreaseImmutableStorageV1 {
96            storage_config: *STORAGE_CONFIG_PDA,
97            storage_account: *storage_account_key,
98            emissions_wallet: emissions_ata,
99            owner: storage_account.owner_1,
100            owner_ata,
101            uploader: UPLOADER,
102            token_mint: TOKEN_MINT,
103            system_program: system_program::ID,
104            token_program: TokenProgramID,
105        };
106        let args = shdw_drive_instructions::IncreaseImmutableStorage {
107            additional_storage: size_as_bytes,
108        };
109
110        let instruction = Instruction {
111            program_id: PROGRAM_ADDRESS,
112            accounts: accounts.to_account_metas(None),
113            data: args.data(),
114        };
115
116        let mut txn = Transaction::new_with_payer(&[instruction], Some(wallet_pubkey));
117
118        txn.try_partial_sign(
119            &[&self.wallet],
120            self.rpc_client.get_latest_blockhash().await?,
121        )?;
122
123        let txn_encoded = serialize_and_encode(&txn)?;
124
125        Ok(txn_encoded)
126    }
127
128    async fn add_immutable_storage_v2(
129        &self,
130        storage_account_key: &Pubkey,
131        storage_account: StorageAccountV2,
132        size_as_bytes: u64,
133    ) -> ShadowDriveResult<String> {
134        let wallet_pubkey = &self.wallet.pubkey();
135        let owner_ata = get_associated_token_address(wallet_pubkey, &TOKEN_MINT);
136        let emissions_ata = get_associated_token_address(&EMISSIONS, &TOKEN_MINT);
137
138        let accounts = shdw_drive_accounts::IncreaseImmutableStorageV2 {
139            storage_config: *STORAGE_CONFIG_PDA,
140            storage_account: *storage_account_key,
141            emissions_wallet: emissions_ata,
142            owner: storage_account.owner_1,
143            owner_ata,
144            uploader: UPLOADER,
145            token_mint: TOKEN_MINT,
146            system_program: system_program::ID,
147            token_program: TokenProgramID,
148        };
149
150        let args = shdw_drive_instructions::IncreaseImmutableStorage2 {
151            additional_storage: size_as_bytes,
152        };
153
154        let instruction = Instruction {
155            program_id: PROGRAM_ADDRESS,
156            accounts: accounts.to_account_metas(None),
157            data: args.data(),
158        };
159
160        let mut txn = Transaction::new_with_payer(&[instruction], Some(wallet_pubkey));
161
162        txn.try_partial_sign(
163            &[&self.wallet],
164            self.rpc_client.get_latest_blockhash().await?,
165        )?;
166
167        let txn_encoded = serialize_and_encode(&txn)?;
168
169        Ok(txn_encoded)
170    }
171}