fireblocks-sdk 2026.3.28

Rust implementation of the Fireblocks SDK
Documentation
use {
    crate::{
        ApiClient,
        Configuration,
        FIREBLOCKS_API,
        FIREBLOCKS_SANDBOX_API,
        apis::{
            Api,
            d_app_connections_api::DAppConnectionsApi,
            transactions_api::{GetTransactionParams, TransactionsApi},
            vaults_api::{GetVaultAccountAssetAddressesPaginatedParams, VaultsApi},
            whitelisted_contracts_api::WhitelistedContractsApi,
            whitelisted_external_wallets_api::WhitelistedExternalWalletsApi,
            whitelisted_internal_wallets_api::WhitelistedInternalWalletsApi,
        },
        error::{self},
        jwt::{JwtSigningMiddleware, Signer},
        models::{AssetTypeResponse, TransactionResponse, VaultWalletAddress},
    },
    jsonwebtoken::EncodingKey,
    std::{sync::Arc, time::Duration},
};

#[derive(Clone)]
pub struct Client {
    api_client: Arc<ApiClient>,
}

mod poll;
mod transfer;
mod vault;
mod whitelist;

pub struct ClientBuilder {
    api_key: String,
    timeout: Duration,
    connect_timeout: Duration,
    user_agent: String,
    secret: Vec<u8>,
    url: String,
}

impl Default for ClientBuilder {
    fn default() -> Self {
        Self {
            api_key: String::new(),
            timeout: Duration::from_secs(15),
            connect_timeout: Duration::from_secs(5),
            user_agent: format!("fireblocks-sdk-rs {}", env!["CARGO_PKG_VERSION"]),
            secret: vec![],
            url: String::from(FIREBLOCKS_API),
        }
    }
}

impl ClientBuilder {
    pub fn new(api_key: &str, secret: &[u8]) -> Self {
        Self {
            api_key: String::from(api_key),
            secret: Vec::from(secret),
            ..Default::default()
        }
    }

    #[allow(unused_mut, clippy::return_self_not_must_use)]
    pub fn use_sandbox(mut self) -> Self {
        self.with_url(FIREBLOCKS_SANDBOX_API)
    }

    #[allow(unused_mut, clippy::return_self_not_must_use)]
    pub fn with_sandbox(mut self) -> Self {
        self.with_url(FIREBLOCKS_SANDBOX_API)
    }

    #[allow(clippy::return_self_not_must_use)]
    pub fn with_url(mut self, url: &str) -> Self {
        self.url = String::from(url);
        self
    }

    #[allow(clippy::return_self_not_must_use)]
    pub const fn with_timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    #[allow(clippy::return_self_not_must_use)]
    pub const fn with_connect_timeout(mut self, timeout: Duration) -> Self {
        self.connect_timeout = timeout;
        self
    }

    #[allow(clippy::return_self_not_must_use)]
    pub fn with_user_agent(mut self, ua: &str) -> Self {
        self.user_agent = String::from(ua);
        self
    }

    pub fn build(self) -> Result<Client, error::FireblocksError> {
        let key = EncodingKey::from_rsa_pem(&self.secret[..])?;
        let signer = Signer::new(key, &self.api_key);
        let jwt_handler = JwtSigningMiddleware::new(signer);
        let r = reqwest::ClientBuilder::new()
            .timeout(self.timeout)
            .connect_timeout(self.connect_timeout)
            .user_agent(String::from(&self.user_agent))
            .build()
            .unwrap_or_default();
        let client = reqwest_middleware::ClientBuilder::new(r)
            .with(crate::log::LoggingMiddleware)
            .with(jwt_handler);
        Ok(Client::new_with_url(
            &self.url,
            client.build(),
            Some(self.user_agent),
        ))
    }
}

impl Client {
    fn new_with_url(
        url: &str,
        client: reqwest_middleware::ClientWithMiddleware,
        user_agent: Option<String>,
    ) -> Self {
        let cfg = Configuration {
            base_path: String::from(url),
            user_agent,
            client,
            basic_auth: None,
            oauth_access_token: None,
            bearer_access_token: None,
            api_key: None,
        };
        let api_client = Arc::new(ApiClient::new(Arc::new(cfg)));
        Self { api_client }
    }
}

impl Client {
    pub async fn get_transaction(&self, id: &str) -> crate::Result<TransactionResponse> {
        let api = self.api_client.transactions_api();
        api.get_transaction(
            GetTransactionParams::builder()
                .tx_id(String::from(id))
                .build(),
        )
        .await
        .map_err(crate::FireblocksError::FetchTransactionError)
    }

    pub async fn supported_assets(&self) -> crate::Result<Vec<AssetTypeResponse>> {
        let api = self.api_client.blockchains_assets_api();
        api.get_supported_assets()
            .await
            .map_err(crate::FireblocksError::FetchSupportedAssetsError)
    }

    pub async fn addresses(
        &self,
        vault_id: &str,
        asset_id: impl Into<String>,
    ) -> crate::Result<Vec<VaultWalletAddress>> {
        let vault_api = self.api_client.vaults_api();
        let params = GetVaultAccountAssetAddressesPaginatedParams::builder()
            .vault_account_id(String::from(vault_id))
            .asset_id(asset_id.into())
            .build();

        let addresses: Option<Vec<VaultWalletAddress>> = vault_api
            .get_vault_account_asset_addresses_paginated(params)
            .await
            .map_err(|e| crate::FireblocksError::FetchAddressesError(e.to_string()))
            .map(|r| r.addresses)?;
        Ok(addresses.unwrap_or_default())
    }

    pub fn transactions_api(&self) -> &dyn TransactionsApi {
        self.api_client.transactions_api()
    }

    pub fn vaults_api(&self) -> &dyn VaultsApi {
        self.api_client.vaults_api()
    }

    pub fn wallet_connect_api(&self) -> &dyn DAppConnectionsApi {
        self.api_client.d_app_connections_api()
    }

    pub fn wallet_internal_api(&self) -> &dyn WhitelistedInternalWalletsApi {
        self.api_client.whitelisted_internal_wallets_api()
    }

    pub fn wallet_external_api(&self) -> &dyn WhitelistedExternalWalletsApi {
        self.api_client.whitelisted_external_wallets_api()
    }

    pub fn wallet_contract_api(&self) -> &dyn WhitelistedContractsApi {
        self.api_client.whitelisted_contracts_api()
    }

    pub fn apis(&self) -> Arc<ApiClient> {
        self.api_client.clone()
    }
}