> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dfns.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Rust SDK

> Server-side SDK for integrating DFNS into Rust backends, with typed clients, request signing, and helpers for wallets, transfers, and signatures.

<Warning>
  **Attention: This project is currently in BETA.**

  This means that while we've worked hard to ensure its functionality, stability, and security, there may still be bugs, performance issues, or unexpected behavior.
</Warning>

The Rust SDK is designed for **server-side/backend** applications. It handles request signing and provides typed access to the DFNS API.

You can find the repository [on GitHub](https://github.com/dfns/dfns-sdk-rust), the crate [on crates.io](https://crates.io/crates/dfns-sdk-rust), and the generated API reference [on docs.rs](https://docs.rs/dfns-sdk-rust).

## Installation

```bash theme={null}
cargo add dfns-sdk-rust
cargo add tokio --features macros,rt-multi-thread
```

The SDK is async and runs on the Tokio runtime. Minimum supported Rust version is 1.75.

## Quick start

### 1. Read-only operations

For read-only operations (listing wallets, fetching balances, etc.), you only need an auth token:

```rust theme={null}
use dfns_sdk_rust::{DfnsClient, Options};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = DfnsClient::new(Options {
        base_url: String::new(), // defaults to https://api.dfns.io
        auth_token: "your-auth-token".to_string(),
        signer: None,
        http: None,
    })?;

    let wallets = client.wallets.list_wallets(None).await?;
    for wallet in wallets.items {
        println!(
            "{}: {} {}",
            wallet.id,
            wallet.network,
            wallet.address.unwrap_or_default()
        );
    }

    Ok(())
}
```

<Tip>
  For a quick test you can get your login token (short-lived) from the [DFNS Dashboard](https://app.dfns.io/) under `Settings` > `Personal Access Tokens`.
</Tip>

### 2. Signing requests

State-changing operations (creating wallets, signing transactions, etc.) require cryptographic request signing. Choose your approach based on where the private key lives:

<Tabs>
  <Tab title="Direct signing">
    Use `DfnsClient` with a signer when your backend has direct access to the private key (e.g., stored in a file or environment variable).

    The SDK does not ship a key signer: you implement the `UserActionSigner` trait with the crypto library of your choice. The client owns the challenge flow and only calls your `sign` method.

    ```rust theme={null}
    use std::sync::Arc;

    use async_trait::async_trait;
    use dfns_sdk_rust::error::Error;
    use dfns_sdk_rust::signer::{CredentialAssertion, UserActionChallenge, UserActionSigner};
    use dfns_sdk_rust::wallets::types::CreateWalletRequest;
    use dfns_sdk_rust::{DfnsClient, Options};

    struct MyKeySigner {
        // your credential ID and private key material
    }

    #[async_trait]
    impl UserActionSigner for MyKeySigner {
        async fn sign(&self, challenge: &UserActionChallenge) -> Result<CredentialAssertion, Error> {
            // Sign challenge.challenge with your credential's private key
            // (e.g. Ed25519 or ECDSA P-256) and return the assertion.
            todo!()
        }
    }

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        let client = DfnsClient::new(Options {
            base_url: String::new(),
            auth_token: "your-auth-token".to_string(),
            signer: Some(Arc::new(MyKeySigner { /* ... */ })),
            http: None,
        })?;

        let wallet = client
            .wallets
            .create_wallet(CreateWalletRequest {
                network: "EthereumSepolia".to_string(),
                name: None,
                signing_key: None,
                delegate_to: None,
                delay_delegation: None,
                external_id: None,
                tags: None,
            })
            .await?;
        println!("Created wallet: {}", wallet.id);

        Ok(())
    }
    ```

    See the [development guide](/sdks/backend/rust/development) for what `sign` must return.
  </Tab>

  <Tab title="Delegated signing">
    Use `DfnsDelegatedClient` when the private key is not directly accessible to your backend:

    * **User passkeys**: Users sign with their own device (WebAuthn/biometrics)
    * **External KMS**: Private key stored in AWS KMS, HashiCorp Vault, etc.

    The delegated client needs no signer. Every operation that requires a user action signature is split into an `_init` / `_complete` pair:

    ```rust theme={null}
    use dfns_sdk_rust::signer::CredentialAssertion;
    use dfns_sdk_rust::wallets::types::CreateWalletRequest;
    use dfns_sdk_rust::{DfnsDelegatedClient, Options};

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        let client = DfnsDelegatedClient::new(Options {
            base_url: String::new(),
            auth_token: "user-auth-token".to_string(),
            signer: None,
            http: None,
        })?;

        let body = CreateWalletRequest {
            network: "EthereumSepolia".to_string(),
            name: None,
            signing_key: None,
            delegate_to: None,
            delay_delegation: None,
            external_id: None,
            tags: None,
        };

        // Step 1 (server): start the action, get a challenge.
        let challenge = client.wallets.create_wallet_init(body.clone()).await?;

        // Step 2 (client): the user signs the challenge and returns the assertion.
        // - For passkeys: send to the user's frontend for WebAuthn signing
        // - For KMS: send to your KMS to sign
        let assertion: CredentialAssertion = sign_challenge_out_of_band(&challenge);

        // Step 3 (server): complete the action with the signed challenge.
        let wallet = client
            .wallets
            .create_wallet_complete(body, challenge.challenge_identifier, assertion)
            .await?;
        println!("Created wallet: {}", wallet.id);

        Ok(())
    }
    ```
  </Tab>
</Tabs>

## Next steps

* **[Create a service account](/guides/developers/service-account)** for server-to-server authentication with long-lived tokens
* **[Development guide](/sdks/backend/rust/development)** for detailed request signing architecture
* **[Delegated wallets](/guides/developers/delegated-wallets)** for implementing user passkey flows
