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}