wallet_rpc/
wallet_rpc.rs

1//! Wallet RPC Example
2//!
3//! This example demonstrates how to sign transactions using Privy's wallet RPC interface.
4//! It shows how to:
5//! - Initialize a Privy client with app credentials
6//! - Submit RPC requests for transaction signing
7//! - Handle RPC responses with signed transaction data
8//!
9//! ## Required Environment Variables
10//! - `PRIVY_APP_ID`: Your Privy app ID
11//! - `PRIVY_APP_SECRET`: Your Privy app secret
12//! - `PRIVY_WALLET_ID`: The wallet ID to use for signing
13//!
14//! ## Usage
15//! ```bash
16//! cargo run --example wallet_rpc
17//! ```
18
19use anyhow::Result;
20use base64::{Engine, engine::general_purpose::STANDARD};
21use privy_rs::{
22    AuthorizationContext, JwtUser, PrivateKey, PrivyApiError, PrivyClient, PrivySignedApiError,
23    generated::types::{
24        SolanaSignMessageRpcInput, SolanaSignMessageRpcInputMethod,
25        SolanaSignMessageRpcInputParams, SolanaSignMessageRpcInputParamsEncoding, WalletRpcBody,
26    },
27};
28use tracing_subscriber::EnvFilter;
29
30#[tokio::main]
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}