Skip to main content

bsv_wallet_toolbox/storage/remoting/
wallet_arc.rs

1//! `WalletArc<W>` — `Clone`-able wrapper for any `WalletInterface` implementor.
2//!
3//! # Problem
4//!
5//! `StorageClient<W>` holds `AuthFetch<W>`, which requires `W: Clone` because it
6//! clones the wallet when creating a BRC-31 `Peer` during each handshake.
7//! `ProtoWallet` (bsv-sdk 0.1.75) does not implement `Clone`, which prevents
8//! `StorageClient<ProtoWallet>` from compiling.
9//!
10//! # Solution
11//!
12//! `WalletArc<W>` wraps any `WalletInterface` in an `Arc<W>` and derives `Clone`
13//! (cheaply — arc ref-count increment). All `WalletInterface` methods are delegated
14//! to the inner `W`. This lets callers use `StorageClient<WalletArc<ProtoWallet>>`
15//! without needing `ProtoWallet: Clone`.
16//!
17//! # Example
18//!
19//! ```rust,ignore
20//! use bsv::primitives::private_key::PrivateKey;
21//! use bsv_wallet_toolbox::ProtoWallet;
22//! use bsv_wallet_toolbox::storage::remoting::{StorageClient, WalletArc};
23//!
24//! let key = PrivateKey::from_random().unwrap();
25//! let proto = ProtoWallet::new(key);
26//! let wallet = WalletArc::new(proto);
27//! let client = StorageClient::new(wallet, "https://staging-storage.babbage.systems");
28//! ```
29
30use std::sync::Arc;
31
32use async_trait::async_trait;
33use bsv::wallet::error::WalletError;
34use bsv::wallet::interfaces::{
35    AbortActionArgs, AbortActionResult, AcquireCertificateArgs, AuthenticatedResult, Certificate,
36    CreateActionArgs, CreateActionResult, CreateHmacArgs, CreateHmacResult, CreateSignatureArgs,
37    CreateSignatureResult, DecryptArgs, DecryptResult, DiscoverByAttributesArgs,
38    DiscoverByIdentityKeyArgs, DiscoverCertificatesResult, EncryptArgs, EncryptResult,
39    GetHeaderArgs, GetHeaderResult, GetHeightResult, GetNetworkResult, GetPublicKeyArgs,
40    GetPublicKeyResult, GetVersionResult, InternalizeActionArgs, InternalizeActionResult,
41    ListActionsArgs, ListActionsResult, ListCertificatesArgs, ListCertificatesResult,
42    ListOutputsArgs, ListOutputsResult, ProveCertificateArgs, ProveCertificateResult,
43    RelinquishCertificateArgs, RelinquishCertificateResult, RelinquishOutputArgs,
44    RelinquishOutputResult, RevealCounterpartyKeyLinkageArgs, RevealCounterpartyKeyLinkageResult,
45    RevealSpecificKeyLinkageArgs, RevealSpecificKeyLinkageResult, SignActionArgs, SignActionResult,
46    VerifyHmacArgs, VerifyHmacResult, VerifySignatureArgs, VerifySignatureResult, WalletInterface,
47};
48
49/// A `Clone`-able wrapper around any `WalletInterface` implementor.
50///
51/// Stores the inner wallet in an `Arc` so cloning is cheap (ref-count increment).
52/// All `WalletInterface` methods are delegated to the inner `W` via deref.
53///
54/// `Clone` is manually implemented (not derived) so that it works even when
55/// `W: !Clone` — `Arc<W>` is always cloneable regardless of `W`.
56///
57/// See module documentation for usage.
58pub struct WalletArc<W: WalletInterface + Send + Sync + 'static>(Arc<W>);
59
60impl<W: WalletInterface + Send + Sync + 'static> Clone for WalletArc<W> {
61    fn clone(&self) -> Self {
62        WalletArc(Arc::clone(&self.0))
63    }
64}
65
66impl<W: WalletInterface + Send + Sync + std::fmt::Debug + 'static> std::fmt::Debug
67    for WalletArc<W>
68{
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        f.debug_tuple("WalletArc").field(&self.0).finish()
71    }
72}
73
74impl<W: WalletInterface + Send + Sync + 'static> WalletArc<W> {
75    /// Wrap a `WalletInterface` implementor in an `Arc`.
76    pub fn new(wallet: W) -> Self {
77        WalletArc(Arc::new(wallet))
78    }
79}
80
81#[async_trait]
82impl<W: WalletInterface + Send + Sync + 'static> WalletInterface for WalletArc<W> {
83    async fn create_action(
84        &self,
85        args: CreateActionArgs,
86        originator: Option<&str>,
87    ) -> Result<CreateActionResult, WalletError> {
88        self.0.create_action(args, originator).await
89    }
90
91    async fn sign_action(
92        &self,
93        args: SignActionArgs,
94        originator: Option<&str>,
95    ) -> Result<SignActionResult, WalletError> {
96        self.0.sign_action(args, originator).await
97    }
98
99    async fn abort_action(
100        &self,
101        args: AbortActionArgs,
102        originator: Option<&str>,
103    ) -> Result<AbortActionResult, WalletError> {
104        self.0.abort_action(args, originator).await
105    }
106
107    async fn list_actions(
108        &self,
109        args: ListActionsArgs,
110        originator: Option<&str>,
111    ) -> Result<ListActionsResult, WalletError> {
112        self.0.list_actions(args, originator).await
113    }
114
115    async fn internalize_action(
116        &self,
117        args: InternalizeActionArgs,
118        originator: Option<&str>,
119    ) -> Result<InternalizeActionResult, WalletError> {
120        self.0.internalize_action(args, originator).await
121    }
122
123    async fn list_outputs(
124        &self,
125        args: ListOutputsArgs,
126        originator: Option<&str>,
127    ) -> Result<ListOutputsResult, WalletError> {
128        self.0.list_outputs(args, originator).await
129    }
130
131    async fn relinquish_output(
132        &self,
133        args: RelinquishOutputArgs,
134        originator: Option<&str>,
135    ) -> Result<RelinquishOutputResult, WalletError> {
136        self.0.relinquish_output(args, originator).await
137    }
138
139    async fn get_public_key(
140        &self,
141        args: GetPublicKeyArgs,
142        originator: Option<&str>,
143    ) -> Result<GetPublicKeyResult, WalletError> {
144        self.0.get_public_key(args, originator).await
145    }
146
147    async fn reveal_counterparty_key_linkage(
148        &self,
149        args: RevealCounterpartyKeyLinkageArgs,
150        originator: Option<&str>,
151    ) -> Result<RevealCounterpartyKeyLinkageResult, WalletError> {
152        self.0
153            .reveal_counterparty_key_linkage(args, originator)
154            .await
155    }
156
157    async fn reveal_specific_key_linkage(
158        &self,
159        args: RevealSpecificKeyLinkageArgs,
160        originator: Option<&str>,
161    ) -> Result<RevealSpecificKeyLinkageResult, WalletError> {
162        self.0.reveal_specific_key_linkage(args, originator).await
163    }
164
165    async fn encrypt(
166        &self,
167        args: EncryptArgs,
168        originator: Option<&str>,
169    ) -> Result<EncryptResult, WalletError> {
170        self.0.encrypt(args, originator).await
171    }
172
173    async fn decrypt(
174        &self,
175        args: DecryptArgs,
176        originator: Option<&str>,
177    ) -> Result<DecryptResult, WalletError> {
178        self.0.decrypt(args, originator).await
179    }
180
181    async fn create_hmac(
182        &self,
183        args: CreateHmacArgs,
184        originator: Option<&str>,
185    ) -> Result<CreateHmacResult, WalletError> {
186        self.0.create_hmac(args, originator).await
187    }
188
189    async fn verify_hmac(
190        &self,
191        args: VerifyHmacArgs,
192        originator: Option<&str>,
193    ) -> Result<VerifyHmacResult, WalletError> {
194        self.0.verify_hmac(args, originator).await
195    }
196
197    async fn create_signature(
198        &self,
199        args: CreateSignatureArgs,
200        originator: Option<&str>,
201    ) -> Result<CreateSignatureResult, WalletError> {
202        self.0.create_signature(args, originator).await
203    }
204
205    async fn verify_signature(
206        &self,
207        args: VerifySignatureArgs,
208        originator: Option<&str>,
209    ) -> Result<VerifySignatureResult, WalletError> {
210        self.0.verify_signature(args, originator).await
211    }
212
213    async fn acquire_certificate(
214        &self,
215        args: AcquireCertificateArgs,
216        originator: Option<&str>,
217    ) -> Result<Certificate, WalletError> {
218        self.0.acquire_certificate(args, originator).await
219    }
220
221    async fn list_certificates(
222        &self,
223        args: ListCertificatesArgs,
224        originator: Option<&str>,
225    ) -> Result<ListCertificatesResult, WalletError> {
226        self.0.list_certificates(args, originator).await
227    }
228
229    async fn prove_certificate(
230        &self,
231        args: ProveCertificateArgs,
232        originator: Option<&str>,
233    ) -> Result<ProveCertificateResult, WalletError> {
234        self.0.prove_certificate(args, originator).await
235    }
236
237    async fn relinquish_certificate(
238        &self,
239        args: RelinquishCertificateArgs,
240        originator: Option<&str>,
241    ) -> Result<RelinquishCertificateResult, WalletError> {
242        self.0.relinquish_certificate(args, originator).await
243    }
244
245    async fn discover_by_identity_key(
246        &self,
247        args: DiscoverByIdentityKeyArgs,
248        originator: Option<&str>,
249    ) -> Result<DiscoverCertificatesResult, WalletError> {
250        self.0.discover_by_identity_key(args, originator).await
251    }
252
253    async fn discover_by_attributes(
254        &self,
255        args: DiscoverByAttributesArgs,
256        originator: Option<&str>,
257    ) -> Result<DiscoverCertificatesResult, WalletError> {
258        self.0.discover_by_attributes(args, originator).await
259    }
260
261    async fn is_authenticated(
262        &self,
263        originator: Option<&str>,
264    ) -> Result<AuthenticatedResult, WalletError> {
265        self.0.is_authenticated(originator).await
266    }
267
268    async fn wait_for_authentication(
269        &self,
270        originator: Option<&str>,
271    ) -> Result<AuthenticatedResult, WalletError> {
272        self.0.wait_for_authentication(originator).await
273    }
274
275    async fn get_height(&self, originator: Option<&str>) -> Result<GetHeightResult, WalletError> {
276        self.0.get_height(originator).await
277    }
278
279    async fn get_header_for_height(
280        &self,
281        args: GetHeaderArgs,
282        originator: Option<&str>,
283    ) -> Result<GetHeaderResult, WalletError> {
284        self.0.get_header_for_height(args, originator).await
285    }
286
287    async fn get_network(&self, originator: Option<&str>) -> Result<GetNetworkResult, WalletError> {
288        self.0.get_network(originator).await
289    }
290
291    async fn get_version(&self, originator: Option<&str>) -> Result<GetVersionResult, WalletError> {
292        self.0.get_version(originator).await
293    }
294}