WalletsClient

Struct WalletsClient 

Source
pub struct WalletsClient { /* private fields */ }
Expand description

Client for wallets operations

Implementations§

Source§

impl WalletsClient

Source

pub async fn rpc<'a>( &'a self, wallet_id: &'a str, ctx: &'a AuthorizationContext, privy_idempotency_key: Option<&'a str>, body: &'a WalletRpcBody, ) -> Result<ResponseValue<WalletRpcResponse>, PrivySignedApiError>

Make a wallet rpc call

§Errors

Can fail either if the authorization signature could not be generated, or if the api call fails whether than be due to network issues, auth problems, or the Privy API returning an error.

Examples found in repository?
examples/wallet_rpc.rs (lines 58-71)
31async fn main() -> Result<()> {
32    tracing_subscriber::fmt()
33        .with_env_filter(
34            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
35        )
36        .init();
37
38    // Get wallet ID from environment
39    let wallet_id =
40        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
41
42    tracing::info!(
43        "initializing privy client from environment, wallet_id: {}",
44        wallet_id
45    );
46
47    let private_key = std::fs::read_to_string("private_key.pem")?;
48
49    let client = PrivyClient::new_from_env()?;
50
51    let ctx = AuthorizationContext::new()
52        .push(PrivateKey(private_key))
53        .push(JwtUser(client.clone(), "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGV4QGFybHlvbi5kZXYiLCJpYXQiOjEwMDAwMDAwMDAwMH0.IpNgavH95CFZPjkzQW4eyxMIfJ-O_5cIaDyu_6KRXffykjYDRwxTgFJuYq0F6d8wSXf4de-vzfBRWSKMISM3rJdlhximYINGJB14mJFCD87VMLFbTpHIXcv7hc1AAYMPGhOsRkYfYXuvVopKszMvhupmQYJ1npSvKWNeBniIyOHYv4xebZD8L0RVlPvuEKTXTu-CDfs2rMwvD9g_wiBznS3uMF3v_KPaY6x0sx9zeCSxAH9zvhMMtct_Ad9kuoUncGpRzNhEk6JlVccN2Leb1JzbldxSywyS2AApD05u-GFAgFDN3P39V3qgRTGDuuUfUvKQ9S4rbu5El9Qq1CJTeA".to_string()));
54
55    // Example: Sign a Solana transaction
56    let rpc_response = match client
57        .wallets()
58        .rpc(
59            &wallet_id,
60            &ctx,
61            None, // No idempotency key
62            &WalletRpcBody::SolanaSignMessageRpcInput(SolanaSignMessageRpcInput {
63                address: Some("7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV".to_string()),
64                chain_type: None,
65                method: SolanaSignMessageRpcInputMethod::SignMessage,
66                params: SolanaSignMessageRpcInputParams {
67                    encoding: SolanaSignMessageRpcInputParamsEncoding::Base64,
68                    message: STANDARD.encode("hello world"),
69                },
70            }),
71        )
72        .await
73    {
74        Ok(r) => r,
75        Err(PrivySignedApiError::Api(PrivyApiError::UnexpectedResponse(resp))) => {
76            tracing::error!("Unexpected response: {:?}", resp.text().await);
77            return Err(anyhow::anyhow!("Unexpected response"));
78        }
79        Err(e) => return Err(e.into()),
80    };
81
82    tracing::info!("RPC response: {:?}", rpc_response);
83
84    Ok(())
85}
Source

pub async fn raw_sign<'a>( &'a self, wallet_id: &'a str, ctx: &'a AuthorizationContext, privy_idempotency_key: Option<&'a str>, body: &'a RawSign, ) -> Result<ResponseValue<RawSignResponse>, PrivySignedApiError>

Make a wallet raw sign call

§Errors

Can fail either if the authorization signature could not be generated, or if the api call fails whether than be due to network issues, auth problems, or the Privy API returning an error.

Examples found in repository?
examples/wallet_raw_sign.rs (lines 54-63)
27async fn main() -> Result<()> {
28    tracing_subscriber::fmt()
29        .with_env_filter(
30            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
31        )
32        .init();
33
34    // Get wallet ID from environment
35    let wallet_id =
36        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
37
38    tracing::info!(
39        "initializing privy client from environment, wallet_id: {}",
40        wallet_id
41    );
42
43    let private_key = std::fs::read_to_string("private_key.pem")?;
44
45    let client = PrivyClient::new_from_env()?;
46
47    let ctx = AuthorizationContext::new()
48        .push(PrivateKey(private_key))
49        .push(JwtUser(client.clone(), "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGV4QGFybHlvbi5kZXYiLCJpYXQiOjEwMDAwMDAwMDAwMH0.IpNgavH95CFZPjkzQW4eyxMIfJ-O_5cIaDyu_6KRXffykjYDRwxTgFJuYq0F6d8wSXf4de-vzfBRWSKMISM3rJdlhximYINGJB14mJFCD87VMLFbTpHIXcv7hc1AAYMPGhOsRkYfYXuvVopKszMvhupmQYJ1npSvKWNeBniIyOHYv4xebZD8L0RVlPvuEKTXTu-CDfs2rMwvD9g_wiBznS3uMF3v_KPaY6x0sx9zeCSxAH9zvhMMtct_Ad9kuoUncGpRzNhEk6JlVccN2Leb1JzbldxSywyS2AApD05u-GFAgFDN3P39V3qgRTGDuuUfUvKQ9S4rbu5El9Qq1CJTeA".to_string()));
50
51    // Example: Sign raw message data
52    let raw_sign_response = match client
53        .wallets()
54        .raw_sign(
55            &wallet_id,
56            &ctx,
57            None, // No idempotency key
58            &RawSign {
59                params: RawSignParams::Variant0 {
60                    hash: "0xdeadbeef".to_string(),
61                },
62            },
63        )
64        .await
65    {
66        Ok(r) => r,
67        Err(PrivySignedApiError::Api(PrivyApiError::UnexpectedResponse(resp))) => {
68            tracing::error!("Unexpected response: {:?}", resp.text().await);
69            return Err(anyhow::anyhow!("Unexpected response"));
70        }
71        Err(e) => return Err(e.into()),
72    };
73
74    tracing::info!("Raw sign response: {:?}", raw_sign_response);
75
76    Ok(())
77}
Source

pub async fn update<'a>( &'a self, wallet_id: &'a str, ctx: &'a AuthorizationContext, body: &'a UpdateWalletBody, ) -> Result<ResponseValue<Wallet>, PrivySignedApiError>

Update a wallet

§Errors

Can fail either if the authorization signature could not be generated, or if the api call fails whether than be due to

Examples found in repository?
examples/update_wallet.rs (lines 62-69)
29async fn main() -> Result<()> {
30    tracing_subscriber::fmt()
31        .with_env_filter(
32            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
33        )
34        .init();
35
36    // Get wallet ID from environment
37    let wallet_id =
38        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
39
40    tracing::info!(
41        "initializing privy client from environment, wallet_id: {}",
42        wallet_id
43    );
44
45    let file = std::fs::read_to_string("private_key.pem")?;
46
47    let key = PrivateKey(file);
48    let public_key = key.get_key().await?.public_key();
49
50    let client = PrivyClient::new_from_env()?;
51
52    let ctx = AuthorizationContext::new()
53        .push(key)
54        .push(JwtUser(client.clone(), "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGV4QGFybHlvbi5kZXYiLCJpYXQiOjEwMDAwMDAwMDAwMH0.IpNgavH95CFZPjkzQW4eyxMIfJ-O_5cIaDyu_6KRXffykjYDRwxTgFJuYq0F6d8wSXf4de-vzfBRWSKMISM3rJdlhximYINGJB14mJFCD87VMLFbTpHIXcv7hc1AAYMPGhOsRkYfYXuvVopKszMvhupmQYJ1npSvKWNeBniIyOHYv4xebZD8L0RVlPvuEKTXTu-CDfs2rMwvD9g_wiBznS3uMF3v_KPaY6x0sx9zeCSxAH9zvhMMtct_Ad9kuoUncGpRzNhEk6JlVccN2Leb1JzbldxSywyS2AApD05u-GFAgFDN3P39V3qgRTGDuuUfUvKQ9S4rbu5El9Qq1CJTeA".to_string()));
55
56    let wallets_client = client.wallets();
57    let wallet = wallets_client.get(&wallet_id).await?;
58
59    tracing::info!("got wallet: {:?}", wallet);
60
61    let wallet = match wallets_client
62        .update(
63            &wallet_id,
64            &ctx,
65            &UpdateWalletBody {
66                owner: Some(OwnerInput::PublicKey(public_key.to_string())),
67                ..Default::default()
68            },
69        )
70        .await
71    {
72        Ok(wallet) => wallet,
73        Err(PrivySignedApiError::Api(PrivyApiError::UnexpectedResponse(r))) => {
74            let text = r.text().await.unwrap_or_default();
75            tracing::warn!("unexpected response: {:?}", text);
76            anyhow::bail!("unexpected response")
77        }
78        Err(e) => {
79            anyhow::bail!("unexpected error: {e:?}")
80        }
81    };
82
83    tracing::info!("got updated wallet: {:?}", wallet);
84
85    Ok(())
86}
Source

pub async fn export<'a>( &'a self, wallet_id: &'a str, ctx: &'a AuthorizationContext, ) -> Result<Vec<u8>, PrivyExportError>

Export a wallet

§Errors

Can fail either if the authorization signature could not be generated, or if the api call fails whether than be due to network issues, auth problems, or the Privy API returning an error. Additionally, if the privy platform were to produce a response from which we cannot decrypt the secret key, a PrivyExportError::Key will be returned.

Examples found in repository?
examples/wallet_export.rs (line 55)
28async fn main() -> Result<()> {
29    tracing_subscriber::fmt()
30        .with_env_filter(
31            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
32        )
33        .init();
34
35    // Get wallet ID from environment
36    let wallet_id =
37        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
38
39    tracing::info!(
40        "initializing privy client from environment, wallet_id: {}",
41        wallet_id
42    );
43
44    tracing::info!("Generated HPKE key pair for encryption");
45
46    let private_key = std::fs::read_to_string("private_key.pem")?;
47
48    let client = PrivyClient::new_from_env()?;
49
50    let ctx = AuthorizationContext::new()
51        .push(PrivateKey(private_key))
52        .push(JwtUser(client.clone(), "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGV4QGFybHlvbi5kZXYiLCJpYXQiOjEwMDAwMDAwMDAwMH0.IpNgavH95CFZPjkzQW4eyxMIfJ-O_5cIaDyu_6KRXffykjYDRwxTgFJuYq0F6d8wSXf4de-vzfBRWSKMISM3rJdlhximYINGJB14mJFCD87VMLFbTpHIXcv7hc1AAYMPGhOsRkYfYXuvVopKszMvhupmQYJ1npSvKWNeBniIyOHYv4xebZD8L0RVlPvuEKTXTu-CDfs2rMwvD9g_wiBznS3uMF3v_KPaY6x0sx9zeCSxAH9zvhMMtct_Ad9kuoUncGpRzNhEk6JlVccN2Leb1JzbldxSywyS2AApD05u-GFAgFDN3P39V3qgRTGDuuUfUvKQ9S4rbu5El9Qq1CJTeA".to_string()));
53
54    // Export wallet private key (requires authorization signature)
55    let secret_key = client.wallets().export(&wallet_id, &ctx).await?;
56
57    tracing::info!("Successfully decrypted private key");
58    tracing::warn!("SECURITY WARNING: Private key exported and decrypted!");
59    println!(
60        "Decrypted private key (hex): {}",
61        secret_key.encode_hex::<String>()
62    );
63
64    Ok(())
65}
More examples
Hide additional examples
examples/quorum_wallet.rs (line 122)
35async fn main() -> Result<()> {
36    tracing_subscriber::fmt()
37        .with_env_filter(
38            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
39        )
40        .init();
41
42    // Initialize client from environment variables
43    let client = PrivyClient::new_from_env()?;
44
45    tracing::info!("initialized privy client from environment");
46
47    // Generate unique identifiers for this example run
48    let timestamp = std::time::SystemTime::now()
49        .duration_since(std::time::SystemTime::UNIX_EPOCH)?
50        .as_secs();
51    let wallet_idempotency_key = format!("quorum-wallet-{}", Uuid::new_v4());
52
53    tracing::info!("Starting quorum wallet example");
54
55    // Step 1: Generate three P-256 private keys for quorum
56    tracing::info!("Generating three P-256 private keys for 2-of-3 quorum");
57    let mut rng = rand::thread_rng();
58    let key1 = SecretKey::<p256::NistP256>::random(&mut rng);
59    let key2 = SecretKey::<p256::NistP256>::random(&mut rng);
60    let key3 = SecretKey::<p256::NistP256>::random(&mut rng);
61
62    let pubkey1 = key1.public_key().to_string();
63    let pubkey2 = key2.public_key().to_string();
64    let pubkey3 = key3.public_key().to_string();
65
66    tracing::info!("Generated public keys:");
67    tracing::info!("Key 1: {}", pubkey1);
68    tracing::info!("Key 2: {}", pubkey2);
69    tracing::info!("Key 3: {}", pubkey3);
70
71    // Step 2: Create a 2-of-3 key quorum
72    tracing::info!("Creating 2-of-3 key quorum");
73
74    let quorum_display_name =
75        CreateKeyQuorumBodyDisplayName::try_from(format!("Quorum Example {timestamp}").as_str())?;
76
77    let quorum_body = CreateKeyQuorumBody {
78        authorization_threshold: Some(2.0), // 2-of-3 threshold
79        display_name: Some(quorum_display_name),
80        public_keys: vec![pubkey1, pubkey2, pubkey3],
81        user_ids: vec![],
82    };
83
84    let key_quorum = client.key_quorums().create(&quorum_body).await?;
85
86    tracing::info!("Created key quorum with ID: {}", key_quorum.id);
87    tracing::info!("Quorum threshold: {:?}", key_quorum.authorization_threshold);
88
89    // Step 3: Create a new Ethereum wallet owned by the quorum
90    tracing::info!(
91        "Creating new Ethereum wallet owned by quorum with idempotency key: {}",
92        wallet_idempotency_key
93    );
94
95    let create_body = CreateWalletBody {
96        chain_type: WalletChainType::Ethereum,
97        additional_signers: None,
98        owner: None,
99        owner_id: Some(key_quorum.id.parse().unwrap()),
100        policy_ids: vec![],
101    };
102
103    let wallet = client
104        .wallets()
105        .create(Some(&wallet_idempotency_key), &create_body)
106        .await?;
107
108    tracing::info!("Created wallet with ID: {}", wallet.id);
109    tracing::info!("Wallet address: {}", wallet.address);
110    tracing::info!("Wallet owner ID: {:?}", wallet.owner_id);
111
112    // Step 4: Test signing with only one key (should fail)
113    tracing::info!("Testing wallet export with only one key (should fail due to quorum threshold)");
114
115    let single_key_ctx = AuthorizationContext::new().push(PrivateKey(
116        key1.to_sec1_pem(der::pem::LineEnding::LF)
117            .unwrap()
118            .as_str()
119            .to_owned(),
120    ));
121
122    let single_key_result = client.wallets().export(&wallet.id, &single_key_ctx).await;
123
124    match single_key_result {
125        Err(err) => {
126            tracing::info!(
127                "✓ Single key authorization correctly failed as expected: {:?}",
128                err
129            );
130        }
131        Ok(_) => {
132            tracing::error!("✗ Single key authorization should have failed but succeeded!");
133            return Err(anyhow::anyhow!(
134                "Single key authorization should have failed due to quorum threshold"
135            ));
136        }
137    }
138
139    // Step 5: Test signing with two keys (should succeed)
140    tracing::info!("Testing wallet export with two keys (should succeed)");
141
142    let two_key_ctx = single_key_ctx.push(PrivateKey(
143        key2.to_sec1_pem(der::pem::LineEnding::LF)
144            .unwrap()
145            .as_str()
146            .to_owned(),
147    ));
148
149    let two_key_result = client.wallets().export(&wallet.id, &two_key_ctx).await;
150
151    match two_key_result {
152        Ok(export_result) => {
153            tracing::info!("✓ Two key authorization succeeded as expected");
154            tracing::info!("Exported private key length: {} bytes", export_result.len());
155        }
156        Err(err) => {
157            tracing::error!("✗ Two key authorization failed unexpectedly: {:?}", err);
158            return Err(anyhow::anyhow!(
159                "Two key authorization should have succeeded"
160            ));
161        }
162    }
163
164    Ok(())
165}
Source

pub async fn import( &self, address: String, private_key_hex: &str, chain_type: WalletImportSupportedChains, owner: Option<WalletImportSubmissionRequestOwner>, policy_ids: Vec<String>, additional_signers: Vec<WalletImportSubmissionRequestAdditionalSignersItem>, ) -> Result<ResponseValue<Wallet>, PrivyApiError>

Import a wallet into the Privy app

§Errors
Source

pub fn ethereum(&self) -> EthereumService

Returns an EthereumService instance for interacting with the Ethereum API

Source

pub fn solana(&self) -> SolanaService

Returns an SolanaService instance for interacting with the Solana API

Source§

impl WalletsClient

Source

pub fn new(client: Client, app_id: String, base_url: String) -> Self

Create a new client instance

Source

pub async fn list<'a>( &'a self, chain_type: Option<GetWalletsChainType>, cursor: Option<&'a GetWalletsCursor>, limit: Option<f64>, user_id: Option<&'a str>, ) -> Result<ResponseValue<GetWalletsResponse>, Error<()>>

Get all wallets

Get all wallets in your app.

Sends a GET request to /v1/wallets

Examples found in repository?
examples/get_wallets.rs (line 45)
25async fn main() -> Result<()> {
26    tracing_subscriber::fmt()
27        .with_env_filter(
28            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
29        )
30        .init();
31
32    // Get additional environment variables and initialize client
33    let wallet_id =
34        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
35    let public_key =
36        std::env::var("PRIVY_PUBLIC_KEY").expect("PRIVY_PUBLIC_KEY environment variable not set");
37    let client = PrivyClient::new_from_env()?;
38
39    tracing::info!(
40        "initialized privy client from environment, wallet_id: {}, public_key: {}",
41        wallet_id,
42        public_key
43    );
44
45    let wallets = client.wallets().list(None, None, Some(5.0), None).await?;
46
47    tracing::info!("got wallets: {:?}", wallets);
48
49    Ok(())
50}
Source

pub async fn create<'a>( &'a self, privy_idempotency_key: Option<&'a str>, body: &'a CreateWalletBody, ) -> Result<ResponseValue<Wallet>, Error<()>>

Create wallet

Create a new wallet.

Sends a POST request to /v1/wallets

Examples found in repository?
examples/create_wallet.rs (lines 41-50)
27async fn main() -> Result<()> {
28    tracing_subscriber::fmt()
29        .with_env_filter(
30            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
31        )
32        .init();
33
34    // Initialize client from environment variables
35    let client = PrivyClient::new_from_env()?;
36
37    tracing::info!("initialized privy client from environment");
38
39    let wallet = client
40        .wallets()
41        .create(
42            None,
43            &CreateWalletBody {
44                chain_type: WalletChainType::Solana,
45                additional_signers: None,
46                owner: None,
47                owner_id: None,
48                policy_ids: vec![],
49            },
50        )
51        .await?;
52
53    tracing::info!("got new wallet: {:?}", wallet);
54
55    Ok(())
56}
More examples
Hide additional examples
examples/quorum_wallet.rs (line 105)
35async fn main() -> Result<()> {
36    tracing_subscriber::fmt()
37        .with_env_filter(
38            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
39        )
40        .init();
41
42    // Initialize client from environment variables
43    let client = PrivyClient::new_from_env()?;
44
45    tracing::info!("initialized privy client from environment");
46
47    // Generate unique identifiers for this example run
48    let timestamp = std::time::SystemTime::now()
49        .duration_since(std::time::SystemTime::UNIX_EPOCH)?
50        .as_secs();
51    let wallet_idempotency_key = format!("quorum-wallet-{}", Uuid::new_v4());
52
53    tracing::info!("Starting quorum wallet example");
54
55    // Step 1: Generate three P-256 private keys for quorum
56    tracing::info!("Generating three P-256 private keys for 2-of-3 quorum");
57    let mut rng = rand::thread_rng();
58    let key1 = SecretKey::<p256::NistP256>::random(&mut rng);
59    let key2 = SecretKey::<p256::NistP256>::random(&mut rng);
60    let key3 = SecretKey::<p256::NistP256>::random(&mut rng);
61
62    let pubkey1 = key1.public_key().to_string();
63    let pubkey2 = key2.public_key().to_string();
64    let pubkey3 = key3.public_key().to_string();
65
66    tracing::info!("Generated public keys:");
67    tracing::info!("Key 1: {}", pubkey1);
68    tracing::info!("Key 2: {}", pubkey2);
69    tracing::info!("Key 3: {}", pubkey3);
70
71    // Step 2: Create a 2-of-3 key quorum
72    tracing::info!("Creating 2-of-3 key quorum");
73
74    let quorum_display_name =
75        CreateKeyQuorumBodyDisplayName::try_from(format!("Quorum Example {timestamp}").as_str())?;
76
77    let quorum_body = CreateKeyQuorumBody {
78        authorization_threshold: Some(2.0), // 2-of-3 threshold
79        display_name: Some(quorum_display_name),
80        public_keys: vec![pubkey1, pubkey2, pubkey3],
81        user_ids: vec![],
82    };
83
84    let key_quorum = client.key_quorums().create(&quorum_body).await?;
85
86    tracing::info!("Created key quorum with ID: {}", key_quorum.id);
87    tracing::info!("Quorum threshold: {:?}", key_quorum.authorization_threshold);
88
89    // Step 3: Create a new Ethereum wallet owned by the quorum
90    tracing::info!(
91        "Creating new Ethereum wallet owned by quorum with idempotency key: {}",
92        wallet_idempotency_key
93    );
94
95    let create_body = CreateWalletBody {
96        chain_type: WalletChainType::Ethereum,
97        additional_signers: None,
98        owner: None,
99        owner_id: Some(key_quorum.id.parse().unwrap()),
100        policy_ids: vec![],
101    };
102
103    let wallet = client
104        .wallets()
105        .create(Some(&wallet_idempotency_key), &create_body)
106        .await?;
107
108    tracing::info!("Created wallet with ID: {}", wallet.id);
109    tracing::info!("Wallet address: {}", wallet.address);
110    tracing::info!("Wallet owner ID: {:?}", wallet.owner_id);
111
112    // Step 4: Test signing with only one key (should fail)
113    tracing::info!("Testing wallet export with only one key (should fail due to quorum threshold)");
114
115    let single_key_ctx = AuthorizationContext::new().push(PrivateKey(
116        key1.to_sec1_pem(der::pem::LineEnding::LF)
117            .unwrap()
118            .as_str()
119            .to_owned(),
120    ));
121
122    let single_key_result = client.wallets().export(&wallet.id, &single_key_ctx).await;
123
124    match single_key_result {
125        Err(err) => {
126            tracing::info!(
127                "✓ Single key authorization correctly failed as expected: {:?}",
128                err
129            );
130        }
131        Ok(_) => {
132            tracing::error!("✗ Single key authorization should have failed but succeeded!");
133            return Err(anyhow::anyhow!(
134                "Single key authorization should have failed due to quorum threshold"
135            ));
136        }
137    }
138
139    // Step 5: Test signing with two keys (should succeed)
140    tracing::info!("Testing wallet export with two keys (should succeed)");
141
142    let two_key_ctx = single_key_ctx.push(PrivateKey(
143        key2.to_sec1_pem(der::pem::LineEnding::LF)
144            .unwrap()
145            .as_str()
146            .to_owned(),
147    ));
148
149    let two_key_result = client.wallets().export(&wallet.id, &two_key_ctx).await;
150
151    match two_key_result {
152        Ok(export_result) => {
153            tracing::info!("✓ Two key authorization succeeded as expected");
154            tracing::info!("Exported private key length: {} bytes", export_result.len());
155        }
156        Err(err) => {
157            tracing::error!("✗ Two key authorization failed unexpectedly: {:?}", err);
158            return Err(anyhow::anyhow!(
159                "Two key authorization should have succeeded"
160            ));
161        }
162    }
163
164    Ok(())
165}
Source

pub async fn get<'a>( &'a self, wallet_id: &'a str, ) -> Result<ResponseValue<Wallet>, Error<()>>

Get wallet

Get a wallet by wallet ID.

Sends a GET request to /v1/wallets/{wallet_id}

Examples found in repository?
examples/get_wallet.rs (line 41)
24async fn main() -> Result<()> {
25    tracing_subscriber::fmt()
26        .with_env_filter(
27            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
28        )
29        .init();
30
31    // Get wallet ID from environment and initialize client
32    let wallet_id =
33        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
34    let client = PrivyClient::new_from_env()?;
35
36    tracing::info!(
37        "initialized privy client from environment, wallet_id: {}",
38        wallet_id
39    );
40
41    let wallet = client.wallets().get(&wallet_id).await?;
42
43    tracing::info!("got wallet: {:?}", wallet);
44
45    Ok(())
46}
More examples
Hide additional examples
examples/update_wallet.rs (line 57)
29async fn main() -> Result<()> {
30    tracing_subscriber::fmt()
31        .with_env_filter(
32            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
33        )
34        .init();
35
36    // Get wallet ID from environment
37    let wallet_id =
38        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
39
40    tracing::info!(
41        "initializing privy client from environment, wallet_id: {}",
42        wallet_id
43    );
44
45    let file = std::fs::read_to_string("private_key.pem")?;
46
47    let key = PrivateKey(file);
48    let public_key = key.get_key().await?.public_key();
49
50    let client = PrivyClient::new_from_env()?;
51
52    let ctx = AuthorizationContext::new()
53        .push(key)
54        .push(JwtUser(client.clone(), "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGV4QGFybHlvbi5kZXYiLCJpYXQiOjEwMDAwMDAwMDAwMH0.IpNgavH95CFZPjkzQW4eyxMIfJ-O_5cIaDyu_6KRXffykjYDRwxTgFJuYq0F6d8wSXf4de-vzfBRWSKMISM3rJdlhximYINGJB14mJFCD87VMLFbTpHIXcv7hc1AAYMPGhOsRkYfYXuvVopKszMvhupmQYJ1npSvKWNeBniIyOHYv4xebZD8L0RVlPvuEKTXTu-CDfs2rMwvD9g_wiBznS3uMF3v_KPaY6x0sx9zeCSxAH9zvhMMtct_Ad9kuoUncGpRzNhEk6JlVccN2Leb1JzbldxSywyS2AApD05u-GFAgFDN3P39V3qgRTGDuuUfUvKQ9S4rbu5El9Qq1CJTeA".to_string()));
55
56    let wallets_client = client.wallets();
57    let wallet = wallets_client.get(&wallet_id).await?;
58
59    tracing::info!("got wallet: {:?}", wallet);
60
61    let wallet = match wallets_client
62        .update(
63            &wallet_id,
64            &ctx,
65            &UpdateWalletBody {
66                owner: Some(OwnerInput::PublicKey(public_key.to_string())),
67                ..Default::default()
68            },
69        )
70        .await
71    {
72        Ok(wallet) => wallet,
73        Err(PrivySignedApiError::Api(PrivyApiError::UnexpectedResponse(r))) => {
74            let text = r.text().await.unwrap_or_default();
75            tracing::warn!("unexpected response: {:?}", text);
76            anyhow::bail!("unexpected response")
77        }
78        Err(e) => {
79            anyhow::bail!("unexpected error: {e:?}")
80        }
81    };
82
83    tracing::info!("got updated wallet: {:?}", wallet);
84
85    Ok(())
86}
Source

pub async fn authenticate_with_jwt<'a>( &'a self, body: &'a AuthenticateBody, ) -> Result<ResponseValue<AuthenticateResponse>, Error<()>>

Obtain a session key to enable wallet access

Obtain a session key to enable wallet access.

Sends a POST request to /v1/wallets/authenticate

Examples found in repository?
examples/jwt_authentication.rs (lines 41-45)
25async fn main() -> Result<()> {
26    tracing_subscriber::fmt()
27        .with_env_filter(
28            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
29        )
30        .init();
31
32    // Get JWT from environment and initialize client
33    let user_jwt =
34        std::env::var("PRIVY_USER_JWT").expect("PRIVY_USER_JWT environment variable not set");
35    let client = PrivyClient::new_from_env()?;
36
37    tracing::info!("initialized privy client from environment");
38
39    let jwt_auth = client
40        .wallets()
41        .authenticate_with_jwt(&AuthenticateBody {
42            user_jwt,
43            encryption_type: None,
44            recipient_public_key: None,
45        })
46        .await?;
47
48    tracing::info!("got jwt auth: {:?}", jwt_auth);
49
50    Ok(())
51}
Source

pub async fn _rpc<'a>( &'a self, wallet_id: &'a str, privy_authorization_signature: Option<&'a str>, privy_idempotency_key: Option<&'a str>, body: &'a WalletRpcBody, ) -> Result<ResponseValue<WalletRpcResponse>, Error<()>>

Create a signature or transaction

Sign a message or transaction with a wallet by wallet ID.

Sends a POST request to /v1/wallets/{wallet_id}/rpc

Source

pub async fn _raw_sign<'a>( &'a self, wallet_id: &'a str, privy_authorization_signature: Option<&'a str>, privy_idempotency_key: Option<&'a str>, body: &'a RawSign, ) -> Result<ResponseValue<RawSignResponse>, Error<()>>

Raw sign

Sign a message with a wallet by wallet ID.

Sends a POST request to /v1/wallets/{wallet_id}/raw_sign

Source

pub async fn _update<'a>( &'a self, wallet_id: &'a str, privy_authorization_signature: Option<&'a str>, body: &'a UpdateWalletBody, ) -> Result<ResponseValue<Wallet>, Error<()>>

Update wallet

Update a wallet’s policies or authorization key configuration.

Sends a PATCH request to /v1/wallets/{wallet_id}

Source

pub async fn _export<'a>( &'a self, wallet_id: &'a str, privy_authorization_signature: Option<&'a str>, body: &'a WalletExportRequestBody, ) -> Result<ResponseValue<WalletExportResponseBody>, Error<()>>

Export wallet

Export a wallet’s private key

Sends a POST request to /v1/wallets/{wallet_id}/export

Source

pub async fn _init_import<'a>( &'a self, body: &'a WalletImportInitializationRequest, ) -> Result<ResponseValue<WalletImportInitializationResponse>, Error<()>>

Initialize import

Initialize a wallet import. Complete by submitting the import.

Sends a POST request to /v1/wallets/import/init

Source

pub async fn _submit_import<'a>( &'a self, body: &'a WalletImportSubmissionRequest, ) -> Result<ResponseValue<Wallet>, Error<()>>

Submit import

Submit a wallet import request.

Sends a POST request to /v1/wallets/import/submit

Source

pub fn transactions(&self) -> WalletsTransactionsClient

Access the transactions subclient

Examples found in repository?
examples/wallet_transactions.rs (line 49)
29async fn main() -> Result<()> {
30    tracing_subscriber::fmt()
31        .with_env_filter(
32            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
33        )
34        .init();
35
36    // Get wallet ID from environment and initialize client
37    let wallet_id =
38        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
39    let client = PrivyClient::new_from_env()?;
40
41    tracing::info!(
42        "initialized privy client from environment, wallet_id: {}",
43        wallet_id
44    );
45
46    // Get SOL transactions on Solana mainnet
47    let transactions = client
48        .wallets()
49        .transactions()
50        .get(
51            &wallet_id,
52            &WalletTransactionsAsset::String(WalletTransactionsAssetString::Sol),
53            WalletTransactionsChain::Base,
54            None,       // No cursor for first page
55            Some(10.0), // Limit to 10 transactions,
56            None,
57        )
58        .await?;
59
60    tracing::info!("got wallet transactions: {:?}", transactions);
61
62    Ok(())
63}
Source

pub fn balance(&self) -> WalletsBalanceClient

Access the balance subclient

Examples found in repository?
examples/wallet_balance.rs (line 50)
30async fn main() -> Result<()> {
31    tracing_subscriber::fmt()
32        .with_env_filter(
33            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
34        )
35        .init();
36
37    // Get wallet ID from environment and initialize client
38    let wallet_id =
39        std::env::var("PRIVY_WALLET_ID").expect("PRIVY_WALLET_ID environment variable not set");
40    let client = PrivyClient::new_from_env()?;
41
42    tracing::info!(
43        "initialized privy client from environment, wallet_id: {}",
44        wallet_id
45    );
46
47    // Get SOL balance on Solana
48    let balance = client
49        .wallets()
50        .balance()
51        .get(
52            &wallet_id,
53            &GetWalletBalanceAsset::String(GetWalletBalanceAssetString::Sol),
54            &GetWalletBalanceChain::String(GetWalletBalanceChainString::Solana),
55            Some(GetWalletBalanceIncludeCurrency::Usd),
56        )
57        .await?;
58
59    tracing::info!("got wallet balance: {:?}", balance);
60
61    Ok(())
62}

Trait Implementations§

Source§

impl Clone for WalletsClient

Source§

fn clone(&self) -> WalletsClient

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WalletsClient

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more