fireblocks_sdk/
client.rs

1use {
2    crate::{
3        ApiClient,
4        Configuration,
5        FIREBLOCKS_API,
6        FIREBLOCKS_SANDBOX_API,
7        apis::{
8            Api,
9            d_app_connections_api::DAppConnectionsApi,
10            transactions_api::{GetTransactionParams, TransactionsApi},
11            vaults_api::{GetVaultAccountAssetAddressesPaginatedParams, VaultsApi},
12            whitelisted_contracts_api::WhitelistedContractsApi,
13            whitelisted_external_wallets_api::WhitelistedExternalWalletsApi,
14            whitelisted_internal_wallets_api::WhitelistedInternalWalletsApi,
15        },
16        error::{self},
17        jwt::{JwtSigningMiddleware, Signer},
18        models::{AssetTypeResponse, TransactionResponse, VaultWalletAddress},
19    },
20    jsonwebtoken::EncodingKey,
21    std::{sync::Arc, time::Duration},
22};
23
24#[derive(Clone)]
25pub struct Client {
26    api_client: Arc<ApiClient>,
27}
28
29mod poll;
30mod transfer;
31mod vault;
32mod whitelist;
33
34pub struct ClientBuilder {
35    api_key: String,
36    timeout: Duration,
37    connect_timeout: Duration,
38    user_agent: String,
39    secret: Vec<u8>,
40    url: String,
41}
42
43impl Default for ClientBuilder {
44    fn default() -> Self {
45        Self {
46            api_key: String::new(),
47            timeout: Duration::from_secs(15),
48            connect_timeout: Duration::from_secs(5),
49            user_agent: format!("fireblocks-sdk-rs {}", env!["CARGO_PKG_VERSION"]),
50            secret: vec![],
51            url: String::from(FIREBLOCKS_API),
52        }
53    }
54}
55
56impl ClientBuilder {
57    pub fn new(api_key: &str, secret: &[u8]) -> Self {
58        Self {
59            api_key: String::from(api_key),
60            secret: Vec::from(secret),
61            ..Default::default()
62        }
63    }
64
65    #[allow(unused_mut, clippy::return_self_not_must_use)]
66    pub fn use_sandbox(mut self) -> Self {
67        self.with_url(FIREBLOCKS_SANDBOX_API)
68    }
69
70    #[allow(unused_mut, clippy::return_self_not_must_use)]
71    pub fn with_sandbox(mut self) -> Self {
72        self.with_url(FIREBLOCKS_SANDBOX_API)
73    }
74
75    #[allow(clippy::return_self_not_must_use)]
76    pub fn with_url(mut self, url: &str) -> Self {
77        self.url = String::from(url);
78        self
79    }
80
81    #[allow(clippy::return_self_not_must_use)]
82    pub const fn with_timeout(mut self, timeout: Duration) -> Self {
83        self.timeout = timeout;
84        self
85    }
86
87    #[allow(clippy::return_self_not_must_use)]
88    pub const fn with_connect_timeout(mut self, timeout: Duration) -> Self {
89        self.connect_timeout = timeout;
90        self
91    }
92
93    #[allow(clippy::return_self_not_must_use)]
94    pub fn with_user_agent(mut self, ua: &str) -> Self {
95        self.user_agent = String::from(ua);
96        self
97    }
98
99    pub fn build(self) -> Result<Client, error::FireblocksError> {
100        let key = EncodingKey::from_rsa_pem(&self.secret[..])?;
101        let signer = Signer::new(key, &self.api_key);
102        let jwt_handler = JwtSigningMiddleware::new(signer);
103        let r = reqwest::ClientBuilder::new()
104            .timeout(self.timeout)
105            .connect_timeout(self.connect_timeout)
106            .user_agent(String::from(&self.user_agent))
107            .build()
108            .unwrap_or_default();
109        let client = reqwest_middleware::ClientBuilder::new(r)
110            .with(crate::log::LoggingMiddleware)
111            .with(jwt_handler);
112        Ok(Client::new_with_url(
113            &self.url,
114            client.build(),
115            Some(self.user_agent),
116        ))
117    }
118}
119
120impl Client {
121    fn new_with_url(
122        url: &str,
123        client: reqwest_middleware::ClientWithMiddleware,
124        user_agent: Option<String>,
125    ) -> Self {
126        let cfg = Configuration {
127            base_path: String::from(url),
128            user_agent,
129            client,
130            basic_auth: None,
131            oauth_access_token: None,
132            bearer_access_token: None,
133            api_key: None,
134        };
135        let api_client = Arc::new(ApiClient::new(Arc::new(cfg)));
136        Self { api_client }
137    }
138}
139
140impl Client {
141    pub async fn get_transaction(&self, id: &str) -> crate::Result<TransactionResponse> {
142        let api = self.api_client.transactions_api();
143        api.get_transaction(
144            GetTransactionParams::builder()
145                .tx_id(String::from(id))
146                .build(),
147        )
148        .await
149        .map_err(crate::FireblocksError::FetchTransactionError)
150    }
151
152    pub async fn supported_assets(&self) -> crate::Result<Vec<AssetTypeResponse>> {
153        let api = self.api_client.blockchains_assets_api();
154        api.get_supported_assets()
155            .await
156            .map_err(crate::FireblocksError::FetchSupportedAssetsError)
157    }
158
159    pub async fn addresses(
160        &self,
161        vault_id: &str,
162        asset_id: impl Into<String>,
163    ) -> crate::Result<Vec<VaultWalletAddress>> {
164        let vault_api = self.api_client.vaults_api();
165        let params = GetVaultAccountAssetAddressesPaginatedParams::builder()
166            .vault_account_id(String::from(vault_id))
167            .asset_id(asset_id.into())
168            .build();
169
170        let addresses: Option<Vec<VaultWalletAddress>> = vault_api
171            .get_vault_account_asset_addresses_paginated(params)
172            .await
173            .map_err(|e| crate::FireblocksError::FetchAddressesError(e.to_string()))
174            .map(|r| r.addresses)?;
175        Ok(addresses.unwrap_or_default())
176    }
177
178    pub fn transactions_api(&self) -> &dyn TransactionsApi {
179        self.api_client.transactions_api()
180    }
181
182    pub fn vaults_api(&self) -> &dyn VaultsApi {
183        self.api_client.vaults_api()
184    }
185
186    pub fn wallet_connect_api(&self) -> &dyn DAppConnectionsApi {
187        self.api_client.d_app_connections_api()
188    }
189
190    pub fn wallet_internal_api(&self) -> &dyn WhitelistedInternalWalletsApi {
191        self.api_client.whitelisted_internal_wallets_api()
192    }
193
194    pub fn wallet_external_api(&self) -> &dyn WhitelistedExternalWalletsApi {
195        self.api_client.whitelisted_external_wallets_api()
196    }
197
198    pub fn wallet_contract_api(&self) -> &dyn WhitelistedContractsApi {
199        self.api_client.whitelisted_contracts_api()
200    }
201
202    pub fn apis(&self) -> Arc<ApiClient> {
203        self.api_client.clone()
204    }
205}