1use {
2 crate::{
3 apis::{
4 d_app_connections_api::DAppConnectionsApi,
5 transactions_api::{GetTransactionParams, TransactionsApi},
6 vaults_api::{GetVaultAccountAssetAddressesPaginatedParams, VaultsApi},
7 whitelisted_contracts_api::WhitelistedContractsApi,
8 whitelisted_external_wallets_api::WhitelistedExternalWalletsApi,
9 whitelisted_internal_wallets_api::WhitelistedInternalWalletsApi,
10 Api,
11 },
12 error::{self},
13 jwt::{JwtSigningMiddleware, Signer},
14 models::{AssetTypeResponse, TransactionResponse, VaultWalletAddress},
15 ApiClient,
16 Configuration,
17 FIREBLOCKS_API,
18 FIREBLOCKS_SANDBOX_API,
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 vault_api
171 .get_vault_account_asset_addresses_paginated(params)
172 .await
173 .map_err(crate::FireblocksError::FetchAddressesError)
174 .map(|r| r.addresses)
175 }
176
177 pub fn transactions_api(&self) -> &dyn TransactionsApi {
178 self.api_client.transactions_api()
179 }
180
181 pub fn vaults_api(&self) -> &dyn VaultsApi {
182 self.api_client.vaults_api()
183 }
184
185 pub fn wallet_connect_api(&self) -> &dyn DAppConnectionsApi {
186 self.api_client.d_app_connections_api()
187 }
188
189 pub fn wallet_internal_api(&self) -> &dyn WhitelistedInternalWalletsApi {
190 self.api_client.whitelisted_internal_wallets_api()
191 }
192
193 pub fn wallet_external_api(&self) -> &dyn WhitelistedExternalWalletsApi {
194 self.api_client.whitelisted_external_wallets_api()
195 }
196
197 pub fn wallet_contract_api(&self) -> &dyn WhitelistedContractsApi {
198 self.api_client.whitelisted_contracts_api()
199 }
200
201 pub fn apis(&self) -> Arc<ApiClient> {
202 self.api_client.clone()
203 }
204}