Skip to main content

foundry_wallets/wallet_browser/
state.rs

1use std::sync::Arc;
2
3use alloy_network::Network;
4use tokio::sync::{Mutex, RwLock};
5use uuid::Uuid;
6
7use crate::wallet_browser::{
8    queue::RequestQueue,
9    types::{
10        BrowserSignRequest, BrowserSignResponse, BrowserTransactionRequest,
11        BrowserTransactionResponse, Connection,
12    },
13};
14
15#[derive(Debug, Clone)]
16pub(crate) struct BrowserWalletState<N: Network> {
17    /// Current information about the wallet connection.
18    connection: Arc<RwLock<Option<Connection>>>,
19    /// Request/response queue for transactions.
20    transactions:
21        Arc<Mutex<RequestQueue<BrowserTransactionRequest<N>, BrowserTransactionResponse>>>,
22    /// Request/response queue for signings.
23    signings: Arc<Mutex<RequestQueue<BrowserSignRequest, BrowserSignResponse>>>,
24    /// Unique session token for the wallet browser instance.
25    /// The CSP on the served page prevents this token from being loaded by other origins.
26    session_token: String,
27    /// If true, the server is running in development mode.
28    /// This relaxes certain security restrictions for local development.
29    ///
30    /// **WARNING**: This should only be used in a development environment.
31    development: bool,
32}
33
34impl<N: Network> BrowserWalletState<N> {
35    /// Create a new browser wallet state.
36    pub fn new(session_token: String, development: bool) -> Self {
37        Self {
38            connection: Arc::new(RwLock::new(None)),
39            transactions: Arc::new(Mutex::new(RequestQueue::new())),
40            signings: Arc::new(Mutex::new(RequestQueue::new())),
41            session_token,
42            development,
43        }
44    }
45
46    /// Get the session token.
47    pub fn session_token(&self) -> &str {
48        &self.session_token
49    }
50
51    /// Check if in development mode.
52    /// This relaxes certain security restrictions for local development.
53    ///
54    /// **WARNING**: This should only be used in a development environment.
55    pub fn is_development(&self) -> bool {
56        self.development
57    }
58
59    /// Check if wallet is connected.
60    pub async fn is_connected(&self) -> bool {
61        self.connection.read().await.is_some()
62    }
63
64    /// Get current connection information.
65    pub async fn get_connection(&self) -> Option<Connection> {
66        *self.connection.read().await
67    }
68
69    /// Set connection information.
70    pub async fn set_connection(&self, connection: Option<Connection>) {
71        *self.connection.write().await = connection;
72    }
73
74    /// Add a transaction request.
75    pub async fn add_transaction_request(&self, request: BrowserTransactionRequest<N>) {
76        self.transactions.lock().await.add_request(request);
77    }
78
79    /// Check if a transaction request exists.
80    pub async fn has_transaction_request(&self, id: &Uuid) -> bool {
81        self.transactions.lock().await.has_request(id)
82    }
83
84    /// Read the next transaction request.
85    pub async fn read_next_transaction_request(&self) -> Option<BrowserTransactionRequest<N>> {
86        self.transactions.lock().await.read_request().cloned()
87    }
88
89    // Remove a transaction request.
90    pub async fn remove_transaction_request(&self, id: &Uuid) {
91        self.transactions.lock().await.remove_request(id);
92    }
93
94    /// Add transaction response.
95    pub async fn add_transaction_response(&self, response: BrowserTransactionResponse) {
96        let id = response.id;
97        let mut transactions = self.transactions.lock().await;
98        transactions.add_response(id, response);
99        transactions.remove_request(&id);
100    }
101
102    /// Get transaction response, removing it from the queue.
103    pub async fn get_transaction_response(&self, id: &Uuid) -> Option<BrowserTransactionResponse> {
104        self.transactions.lock().await.get_response(id)
105    }
106
107    /// Add a signing request.
108    pub async fn add_signing_request(&self, request: BrowserSignRequest) {
109        self.signings.lock().await.add_request(request);
110    }
111
112    /// Check if a signing request exists.
113    pub async fn has_signing_request(&self, id: &Uuid) -> bool {
114        self.signings.lock().await.has_request(id)
115    }
116
117    /// Read the next signing request.
118    pub async fn read_next_signing_request(&self) -> Option<BrowserSignRequest> {
119        self.signings.lock().await.read_request().cloned()
120    }
121
122    /// Remove a signing request.
123    pub async fn remove_signing_request(&self, id: &Uuid) {
124        self.signings.lock().await.remove_request(id);
125    }
126
127    /// Add signing response.
128    pub async fn add_signing_response(&self, response: BrowserSignResponse) {
129        let id = response.id;
130        let mut signings = self.signings.lock().await;
131        signings.add_response(id, response);
132        signings.remove_request(&id);
133    }
134
135    /// Get signing response, removing it from the queue.
136    pub async fn get_signing_response(&self, id: &Uuid) -> Option<BrowserSignResponse> {
137        self.signings.lock().await.get_response(id)
138    }
139}