shadow_drive_user_staking/instructions/
update_account.rs1use anchor_lang::prelude::*;
2use anchor_lang::solana_program::program::invoke;
3use anchor_lang::solana_program::system_instruction::transfer;
4use anchor_spl::token::Mint;
5
6use crate::constants::*;
7use crate::errors::ErrorCodes;
8use crate::instructions::{
9 initialize_account::{ShadowDriveStorageAccount, StorageAccount, StorageAccountV2}, initialize_config::StorageConfig,
10};
11
12pub fn handler(
14 mut ctx: impl UpdateAccount,
15 identifier: Option<String>,
16 owner_2: Option<Pubkey>,
17 ) -> Result<()> {
20 require!(
22 !ctx.check_immutable(),
23 ErrorCodes::StorageAccountMarkedImmutable
24 );
25
26 msg!(
27 "Updating StorageAccount: {}",
28 ctx.get_identifier()
29 );
30
31 ctx.update_identifier(identifier)?;
33
34 if let Some(owner_2) = owner_2 {
36 ctx.update_owner2(owner_2)?;
37 }
38
39 Ok(())
40}
41
42#[derive(Accounts)]
43pub struct UpdateAccountV1<'info> {
46 #[account(
48 seeds = [
49 "storage-config".as_bytes()
50 ],
51 bump,
52 )]
53 pub storage_config: Box<Account<'info, StorageConfig>>,
54
55 #[account(
57 mut,
58 seeds = [
59 "storage-account".as_bytes(),
60 &storage_account.owner_1.key().to_bytes(),
61 &storage_account.account_counter_seed.to_le_bytes()
62 ],
63 bump,
64 )]
65 pub storage_account: Box<Account<'info, StorageAccount>>,
66
67 #[account(mut, constraint=storage_account.is_owner(owner.key()))]
70 pub owner: Signer<'info>,
71
72 #[account(address = shdw::ID)]
74 pub token_mint: Account<'info, Mint>,
75
76 pub system_program: Program<'info, System>,
78}
79
80
81#[derive(Accounts)]
82pub struct UpdateAccountV2<'info> {
85 #[account(
87 seeds = [
88 "storage-config".as_bytes()
89 ],
90 bump,
91 )]
92 pub storage_config: Box<Account<'info, StorageConfig>>,
93
94 #[account(
96 mut,
97 seeds = [
98 "storage-account".as_bytes(),
99 &storage_account.owner_1.key().to_bytes(),
100 &storage_account.account_counter_seed.to_le_bytes()
101 ],
102 bump,
103 )]
104 pub storage_account: Box<Account<'info, StorageAccountV2>>,
105
106 #[account(mut, constraint=storage_account.is_owner(owner.key()))]
109 pub owner: Signer<'info>,
110
111 #[account(address = shdw::ID)]
113 pub token_mint: Account<'info, Mint>,
114
115 pub system_program: Program<'info, System>,
117}
118
119pub trait UpdateAccount {
120 fn check_immutable(&self) -> bool;
121 fn get_identifier(&self) -> String;
122 fn update_identifier(&mut self, identifier: Option<String>) -> Result<()>;
123 fn update_owner2(&mut self, owner_2: Pubkey) -> Result<()>;
124}
125
126impl UpdateAccount for Context<'_,'_,'_,'_, UpdateAccountV1<'_>> {
127 fn check_immutable(&self) -> bool {
128 self.accounts.storage_account.check_immutable()
129 }
130 fn get_identifier(&self) -> String {
131 self.accounts.storage_account.get_identifier()
132 }
133 fn update_identifier(&mut self, identifier: Option<String>) -> Result<()> {
134
135 if let Some(identifier) = identifier {
136
137 let account_info = self.accounts.storage_account.to_account_info();
138
139 let new_size = crate::instructions::initialize_account::calc_v1_storage(&identifier);
141 let current_size = crate::instructions::initialize_account::calc_v1_storage(&self.accounts.storage_account.identifier);
142
143 msg!("Renaming account from {} to {}", self.accounts.storage_account.identifier, identifier);
145 self.accounts.storage_account.identifier = identifier;
146
147 let rent = Rent::default();
149 let min_balance: u64 = rent.minimum_balance(new_size);
150 let current_balance: u64 = account_info.lamports();
151
152
153 if current_balance > min_balance {
155
156
157 let mut user_balance = self.accounts.owner.try_borrow_mut_lamports()?;
158 let mut account_balance = account_info.try_borrow_mut_lamports()?;
159
160 let diff = current_balance.checked_sub(min_balance).unwrap();
161 **user_balance = user_balance.checked_add(diff).unwrap();
162 **account_balance = account_balance.checked_sub(diff).unwrap();
163
164 } else if current_balance < min_balance {
166
167 let ix = transfer(
169 &self.accounts.owner.key(),
170 &self.accounts.storage_account.key(),
171 min_balance.checked_sub(current_balance).unwrap(),
172 );
173
174 invoke(
176 &ix,
177 &[
178 self.accounts.owner.to_account_info(),
179 self.accounts.storage_account.to_account_info(),
180 ],
181 )?;
182 }
183
184 if new_size != current_size {
185 account_info.realloc(new_size, false)?;
186 }
187 }
188
189
190 Ok(())
191 }
192 fn update_owner2(&mut self, owner_2: Pubkey) -> Result<()> {
193 self.accounts.storage_account.owner_2 = owner_2;
194 Ok(())
195 }
196}
197
198impl UpdateAccount for Context<'_,'_,'_,'_, UpdateAccountV2<'_>> {
199 fn check_immutable(&self) -> bool {
200 self.accounts.storage_account.check_immutable()
201 }
202 fn get_identifier(&self) -> String {
203 self.accounts.storage_account.get_identifier()
204 }
205 fn update_identifier(&mut self, identifier: Option<String>) -> Result<()> {
206
207 if let Some(identifier) = identifier {
208
209 let account_info = self.accounts.storage_account.to_account_info();
210
211 let new_size = crate::instructions::initialize_account::calc_v2_storage(&identifier);
213 let current_size = crate::instructions::initialize_account::calc_v2_storage(&self.accounts.storage_account.identifier);
214
215 msg!("Renaming account from {} to {}", self.accounts.storage_account.identifier, identifier);
217 self.accounts.storage_account.identifier = identifier;
218
219 let rent = Rent::default();
221 let min_balance: u64 = rent.minimum_balance(new_size);
222 let current_balance: u64 = account_info.lamports();
223
224
225 if current_balance > min_balance {
227
228
229 let mut user_balance = self.accounts.owner.try_borrow_mut_lamports()?;
230 let mut account_balance = account_info.try_borrow_mut_lamports()?;
231
232 let diff = current_balance.checked_sub(min_balance).unwrap();
233 **user_balance = user_balance.checked_add(diff).unwrap();
234 **account_balance = account_balance.checked_sub(diff).unwrap();
235
236 } else if current_balance < min_balance {
238
239 let ix = transfer(
241 &self.accounts.owner.key(),
242 &self.accounts.storage_account.key(),
243 min_balance.checked_sub(current_balance).unwrap(),
244 );
245
246 invoke(
248 &ix,
249 &[
250 self.accounts.owner.to_account_info(),
251 self.accounts.storage_account.to_account_info(),
252 ],
253 )?;
254 }
255
256 if new_size != current_size {
257 account_info.realloc(new_size, false)?;
258 }
259 }
260
261 Ok(())
262 }
263 fn update_owner2(&mut self, _owner_2: Pubkey) -> Result<()> {
264 err!(ErrorCodes::OnlyOneOwnerAllowedInV1_5)
265 }
266}
267