fireblocks-solana-signer

Crates.iofireblocks-solana-signer
lib.rsfireblocks-solana-signer
version2.0.1
created_at2025-06-29 08:50:02.068711+00
updated_at2025-12-02 07:19:25.025486+00
descriptionImplementation of a Solana Signer using Fireblocks as backend signer
homepagehttps://github.com/CarteraMesh/fireblocks-solana-signer
repositoryhttps://github.com/CarteraMesh/fireblocks-solana-signer
max_upload_size
id1730557
size287,031
Douglas Chimento (dougEfresh)

documentation

https://docs.rs/fireblocks-solana-signer

README

fireblocks-solana-signer

docs build deps codecov crate

Overview

Implementation of a Solana Signer using Fireblocks as backend signer

Prerequisites

A fireblocks account with API key. See developer portal and sign up for a sandbox account

Installation

Add this to your Cargo.toml:

[dependencies]
fireblocks-solana-signer = "1"

Or install via cargo:

cargo add fireblocks-solana-signer@1

TLDR

use {
    fireblocks_solana_sdk::signature::FireblocksSigner,
    solana_sdk::message::Message,
    solana_client::rpc_client::{RpcClient, SerializableTransaction},
    solana_sdk::instruction::Instruction,
    solana_sdk::transaction::Transaction,
};

fn memo(message: &str) -> Instruction {
    Instruction {
        program_id: spl_memo_interface::v3::id(),
        accounts: vec![],
        data: message.as_bytes().to_vec(),
    }
}

fn main() -> anyhow::Result<()> {
    let signer: FireblocksSigner = FireblocksSigner::try_from_env(None)?;
    let rpc = RpcClient::new(
        std::env::var("RPC_URL")
            .ok()
            .unwrap_or("https://rpc.ankr.com/solana_devnet".to_string()),
    );
    let hash = rpc.get_latest_blockhash()?;
    let message = Message::new(&[memo("fireblocks signer")], Some(&signer.pk));
    let mut tx = Transaction::new_unsigned(message);

    tx.try_sign(&[&signer], hash)?;
    rpc.send_transaction(&tx)?;

    Ok(())
}

See example

Transaction Broadcasting

By default, this signer only signs transactions and does not broadcast them. You control when transactions are sent to the network by calling rpc.send_transaction() yourself.

To enable automatic broadcasting (where Fireblocks signs and broadcasts in one step), set:

  • Environment variable: FIREBLOCKS_BROADCAST=true
  • Config file: broadcast = true in the [signer] section

When auto-broadcasting is enabled, transactions are sent to the network immediately after signing, and you should not call send_transaction() yourself.

Environment Variables

Var Example
FIREBLOCKS_SECRET RSA private key of your API user
FIREBLOCKS_API_KEY uuid of api user
FIREBLOCKS_ENDPOINT https://sandbox-api.fireblocks.io
FIREBLOCKS_PUBKEY optional pubkey, or lookup based on FIREBLOCKS_VAULT
FIREBLOCKS_DEVNET set to any value if you are on devnet
FIREBLOCKS_VAULT your vault id
FIREBLOCKS_POLL_TIMEOUT in seconds, total time to check status of transaction
FIREBLOCKS_POLL_INTERVAL in seconds
FIREBLOCKS_BROADCAST set to "true" to auto-broadcast transactions (default: false)

Configuration Files (Optional)

As an alternative to environment variables, you can use configuration files with the config feature. This provides a more structured approach to managing multiple Fireblocks environments and credentials.

Enabling the Config Feature

Add the config feature to your Cargo.toml:

[dependencies]
fireblocks-solana-signer = { version = "1", features = ["config"] }

Configuration File Setup

The config feature uses the fireblocks-config crate for configuration management. Configuration files are stored in the ~/.config/fireblocks/ directory using the microxdg crate.

File Structure:

  • Default configuration: ~/.config/fireblocks/default.toml (always loaded)
  • Profile configurations: ~/.config/fireblocks/{profile}.toml (override default settings)

Example ~/.config/fireblocks/default.toml:

api_key = "your-sandbox-api-key-uuid"
secret_path = "/path/to/your/sandbox-private-key.pem"
url = "https://sandbox-api.fireblocks.io"
mainnet = false

[signer]
vault = "your-sandbox-vault-id"
poll_timeout = 30
poll_interval = 2
broadcast = false # default is false

Example ~/.config/fireblocks/production.toml:

api_key = "your-production-api-key"
secret_path = "/path/to/production-key.pem"
url = "https://api.fireblocks.io"
mainnet = true

[signer]
vault = "your-production-vault-id"
poll_timeout = 60
poll_interval = 3
broadcast = true

Using Configuration Files

use fireblocks_solana_sdk::signature::FireblocksSigner;

fn main() -> anyhow::Result<()> {
    // Use default configuration profile
    let signer = FireblocksSigner::try_from_config::<String>(
        &[],
        |tx_response| println!("Transaction status: {}", tx_response)
    )?;

    // Use specific configuration profiles
    let signer = FireblocksSigner::try_from_config(
        &["mainnet"],
        |tx_response| eprintln!("Mainnet TX: {}", tx_response)
    )?;

    // Use multiple profiles (later profiles override earlier ones)
    let signer = FireblocksSigner::try_from_config(
        &["default", "production"],
        |tx_response| println!("TX Update: {}", tx_response)
    )?;

    // Your transaction code here...
    Ok(())
}

How Profile Loading Works:

  • Empty slice &[]: Loads only ~/.config/fireblocks/default.toml
  • Single profile &["production"]: Loads default.toml first, then production.toml overrides any matching settings
  • Multiple profiles &["staging", "production"]: Loads default.toml, then staging.toml, then production.toml (each overriding previous values)

Benefits of Configuration Files

  • Multiple Environments: Easily switch between sandbox, testnet, and mainnet
  • Profile Management: Organize different configurations by environment or use case
  • Version Control: Configuration files can be committed (without secrets) for team sharing
  • Validation: Built-in validation and error handling for configuration values
  • Flexibility: Override specific settings per profile while inheriting defaults

Configuration vs Environment Variables

Method Best For Pros Cons
Environment Variables Simple setups, CI/CD Easy to set, widely supported Hard to manage multiple environments
Configuration Files Complex setups, multiple environments Organized, version-controllable, flexible Requires additional feature, more setup

For detailed configuration options and file locations, see the fireblocks-config documentation.

Development

Prerequisites

  • Rust Nightly: Required for code formatting with advanced features

    rustup install nightly
    
  • Environment Setup: Create a .env file with your Fireblocks credentials

    cp env-sample .env
    # Edit .env with your actual Fireblocks API credentials
    

Getting Started

  1. Clone the repository

    git clone https://github.com/CarteraMesh/fireblocks-solana-signer.git
    cd fireblocks-solana-signer
    
  2. Set up environment

    # Copy and configure environment variables
    cp env-sample .env
    
    # Install Rust nightly for formatting
    rustup install nightly
    
  3. Build and test

    # Build the project
    cargo build
    
    # Run tests (requires valid Fireblocks credentials in .env)
    cargo test
    
    # Format code (requires nightly)
    cargo +nightly fmt --all
    

Code Formatting

This project uses advanced Rust formatting features that require nightly:

# Format all code
cargo +nightly fmt --all

# Check formatting
cargo +nightly fmt --all -- --check

Running Examples

# Make sure your .env file is configured first
cargo run --example memo
Commit count: 0

cargo fmt