shadow_drive_sdk/client/
migrate.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};
7
8use super::ShadowDriveClient;
9
10use crate::{constants::PROGRAM_ADDRESS, derived_addresses, models::*};
11
12impl<T> ShadowDriveClient<T>
13where
14    T: Signer,
15{
16    /// Migrates a v1 [`StorageAccount`](crate::models::StorageAccount) to v2.
17    /// This requires two separate transactions to reuse the original pubkey. To minimize chance of failure, it is recommended to call this method with a [commitment level][cl] of [`Finalized`](solana_sdk::commitment_config::CommitmentLevel::Finalized)
18    ///
19    /// [cl]: https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment
20    ///
21    /// * `storage_account_key` - The public key of the [`StorageAccount`](crate::models::StorageAccount) to be migrated.
22    ///
23    /// # Example
24    ///
25    /// ```
26    /// # use shadow_drive_rust::{ShadowDriveClient, derived_addresses::storage_account};
27    /// # use solana_client::rpc_client::RpcClient;
28    /// # use solana_sdk::{
29    /// # pubkey::Pubkey,
30    /// # signature::Keypair,
31    /// # signer::{keypair::read_keypair_file, Signer},
32    /// # };
33    /// #
34    /// # let keypair = read_keypair_file(KEYPAIR_PATH).expect("failed to load keypair at path");
35    /// # let user_pubkey = keypair.pubkey();
36    /// # let rpc_client = RpcClient::new("https://ssc-dao.genesysgo.net");
37    /// # let shdw_drive_client = ShadowDriveClient::new(keypair, rpc_client);
38    /// # let (storage_account_key, _) = storage_account(&user_pubkey, 0);
39    /// #
40    ///let migrate_response = shdw_drive_client
41    ///     .migrate(&storage_account_key)
42    ///     .await?;
43    /// ```
44    pub async fn migrate(
45        &self,
46        storage_account_key: &Pubkey,
47    ) -> ShadowDriveResult<(ShdwDriveResponse, ShdwDriveResponse)> {
48        let step_1_response = self.migrate_step_1(storage_account_key).await?;
49        let step_2_response = self.migrate_step_2(storage_account_key).await?;
50        Ok((step_1_response, step_2_response))
51    }
52
53    /// First transaction step that migrates a v1 [`StorageAccount`](crate::models::StorageAccount) to v2.
54    /// Consists of copying the existing account's data into an intermediate account, and deleting the v1 storage account
55    pub async fn migrate_step_1(
56        &self,
57        storage_account_key: &Pubkey,
58    ) -> ShadowDriveResult<ShdwDriveResponse> {
59        let wallet_pubkey = self.wallet.pubkey();
60        let (migration, _) = derived_addresses::migration_helper(storage_account_key);
61
62        let accounts = shdw_drive_accounts::MigrateStep1 {
63            storage_account: *storage_account_key,
64            migration,
65            owner: wallet_pubkey,
66            system_program: system_program::ID,
67        };
68
69        let args = shdw_drive_instructions::MigrateStep1 {};
70
71        let instruction = Instruction {
72            program_id: PROGRAM_ADDRESS,
73            accounts: accounts.to_account_metas(None),
74            data: args.data(),
75        };
76
77        let mut txn = Transaction::new_with_payer(&[instruction], Some(&wallet_pubkey));
78        txn.try_sign(
79            &[&self.wallet],
80            self.rpc_client.get_latest_blockhash().await?,
81        )?;
82        let txn_result = self.rpc_client.send_and_confirm_transaction(&txn).await?;
83
84        Ok(ShdwDriveResponse {
85            txid: txn_result.to_string(),
86        })
87    }
88    /// Second transaction step that migrates a v1 [`StorageAccount`](crate::models::StorageAccount) to v2.
89    /// Consists of recreating the storage account using the original pubkey, and deleting the intermediate account
90    pub async fn migrate_step_2(
91        &self,
92        storage_account_key: &Pubkey,
93    ) -> ShadowDriveResult<ShdwDriveResponse> {
94        let wallet_pubkey = self.wallet.pubkey();
95        let (migration, _) = derived_addresses::migration_helper(storage_account_key);
96
97        let accounts = shdw_drive_accounts::MigrateStep2 {
98            storage_account: *storage_account_key,
99            migration,
100            owner: wallet_pubkey,
101            system_program: system_program::ID,
102        };
103
104        let args = shdw_drive_instructions::MigrateStep2 {};
105
106        let instruction = Instruction {
107            program_id: PROGRAM_ADDRESS,
108            accounts: accounts.to_account_metas(None),
109            data: args.data(),
110        };
111
112        let mut txn = Transaction::new_with_payer(&[instruction], Some(&wallet_pubkey));
113        txn.try_sign(
114            &[&self.wallet],
115            self.rpc_client.get_latest_blockhash().await?,
116        )?;
117        let txn_result = self.rpc_client.send_and_confirm_transaction(&txn).await?;
118
119        Ok(ShdwDriveResponse {
120            txid: txn_result.to_string(),
121        })
122    }
123}