privy_rs/subclients/
wallets.rs

1use super::{Error, ResponseValue, types};
2use crate::{
3    AuthorizationContext, PrivyApiError, PrivyExportError, PrivyHpke, PrivySignedApiError,
4    ethereum::EthereumService,
5    generate_authorization_signatures,
6    generated::types::{
7        HpkeEncryption, PrivateKeyInitInput, Wallet, WalletExportRequestBody,
8        WalletImportSubmissionRequestAdditionalSignersItem, WalletImportSubmissionRequestOwner,
9        WalletImportSupportedChains,
10    },
11    import::WalletImport,
12    solana::SolanaService,
13    subclients::WalletsClient,
14};
15
16impl WalletsClient {
17    /// Make a wallet rpc call
18    ///
19    /// # Errors
20    ///
21    /// Can fail either if the authorization signature could not be generated,
22    /// or if the api call fails whether than be due to network issues, auth problems,
23    /// or the Privy API returning an error.
24    pub async fn rpc<'a>(
25        &'a self,
26        wallet_id: &'a str,
27        ctx: &'a AuthorizationContext,
28        privy_idempotency_key: Option<&'a str>,
29        body: &'a crate::generated::types::WalletRpcBody,
30    ) -> Result<ResponseValue<crate::generated::types::WalletRpcResponse>, PrivySignedApiError>
31    {
32        let sig = generate_authorization_signatures(
33            ctx,
34            &self.app_id,
35            crate::Method::POST,
36            format!("{}/v1/wallets/{}/rpc", self.base_url, wallet_id),
37            body,
38            privy_idempotency_key.map(|k| k.to_owned()),
39        )
40        .await?;
41
42        Ok(self
43            ._rpc(wallet_id, Some(&sig), privy_idempotency_key, body)
44            .await?)
45    }
46
47    /// Make a wallet raw sign call
48    ///
49    /// # Errors
50    ///
51    /// Can fail either if the authorization signature could not be generated,
52    /// or if the api call fails whether than be due to network issues, auth problems,
53    /// or the Privy API returning an error.
54    pub async fn raw_sign<'a>(
55        &'a self,
56        wallet_id: &'a str,
57        ctx: &'a AuthorizationContext,
58        privy_idempotency_key: Option<&'a str>,
59        body: &'a crate::generated::types::RawSign,
60    ) -> Result<ResponseValue<crate::generated::types::RawSignResponse>, PrivySignedApiError> {
61        let sig = generate_authorization_signatures(
62            ctx,
63            &self.app_id,
64            crate::Method::POST,
65            format!("{}/v1/wallets/{}/raw_sign", self.base_url, wallet_id),
66            body,
67            privy_idempotency_key.map(|k| k.to_owned()),
68        )
69        .await?;
70
71        Ok(self
72            ._raw_sign(wallet_id, Some(&sig), privy_idempotency_key, body)
73            .await?)
74    }
75
76    /// Update a wallet
77    ///
78    /// # Errors
79    ///
80    /// Can fail either if the authorization signature could not be generated,
81    /// or if the api call fails whether than be due to
82    pub async fn update<'a>(
83        &'a self,
84        wallet_id: &'a str,
85        ctx: &'a AuthorizationContext,
86        body: &'a crate::generated::types::UpdateWalletBody,
87    ) -> Result<ResponseValue<crate::generated::types::Wallet>, PrivySignedApiError> {
88        let sig = generate_authorization_signatures(
89            ctx,
90            &self.app_id,
91            crate::Method::PATCH,
92            format!("{}/v1/wallets/{}", self.base_url, wallet_id),
93            body,
94            None,
95        )
96        .await?;
97
98        Ok(self._update(wallet_id, Some(&sig), body).await?)
99    }
100
101    /// Export a wallet
102    ///
103    /// # Errors
104    ///
105    /// Can fail either if the authorization signature could not be generated,
106    /// or if the api call fails whether than be due to network issues, auth problems,
107    /// or the Privy API returning an error. Additionally, if the privy platform
108    /// were to produce a response from which we cannot decrypt the secret key,
109    /// a `PrivyExportError::Key` will be returned.
110    pub async fn export<'a>(
111        &'a self,
112        wallet_id: &'a str,
113        ctx: &'a AuthorizationContext,
114    ) -> Result<Vec<u8>, PrivyExportError> {
115        let privy_hpke = PrivyHpke::new();
116        let body = WalletExportRequestBody {
117            encryption_type: HpkeEncryption::Hpke,
118            recipient_public_key: privy_hpke.public_key()?,
119        };
120
121        let sig = generate_authorization_signatures(
122            ctx,
123            &self.app_id,
124            crate::Method::POST,
125            format!("{}/v1/wallets/{}/export", self.base_url, wallet_id),
126            &body,
127            None,
128        )
129        .await?;
130
131        let resp = self._export(wallet_id, Some(&sig), &body).await?;
132
133        tracing::debug!("Encapsulated key: {:?}", resp);
134
135        Ok(privy_hpke.decrypt_raw(&resp.encapsulated_key, &resp.ciphertext)?)
136    }
137
138    /// Import a wallet into the Privy app
139    ///
140    /// # Errors
141    pub async fn import(
142        &self,
143        address: String,
144        private_key_hex: &str,
145        chain_type: WalletImportSupportedChains,
146        owner: Option<WalletImportSubmissionRequestOwner>,
147        policy_ids: Vec<String>,
148        additional_signers: Vec<WalletImportSubmissionRequestAdditionalSignersItem>,
149    ) -> Result<ResponseValue<Wallet>, PrivyApiError> {
150        WalletImport::new(
151            self.clone(),
152            crate::generated::types::WalletImportInitializationRequest::PrivateKeyInitInput(
153                PrivateKeyInitInput {
154                    address: address.clone(),
155                    chain_type,
156                    encryption_type: HpkeEncryption::Hpke,
157                    entropy_type:
158                        crate::generated::types::PrivateKeyInitInputEntropyType::PrivateKey,
159                },
160            ),
161        )
162        .await?
163        .submit(private_key_hex, owner, policy_ids, additional_signers)
164        .await
165    }
166
167    pub(crate) async fn submit_import<'a>(
168        &'a self,
169        body: &'a types::WalletImportSubmissionRequest,
170    ) -> Result<ResponseValue<types::Wallet>, Error<()>> {
171        self._submit_import(body).await
172    }
173
174    /// Returns an `EthereumService` instance for interacting with the Ethereum API
175    pub fn ethereum(&self) -> EthereumService {
176        EthereumService::new(self.clone())
177    }
178
179    /// Returns an `SolanaService` instance for interacting with the Solana API
180    pub fn solana(&self) -> SolanaService {
181        SolanaService::new(self.clone())
182    }
183}