Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dfns Rust SDK

Crates.io Downloads docs.rs Rust Build lint Coverage MSRV License: MIT

Welcome, builders. This repo holds the Dfns Rust SDK. Useful links:

Installation

cargo add dfns-sdk-rust

Quick Start

use dfns_sdk_rust::{DfnsClient, Options};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create the client (read-only operations)
    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,
    })?;

    // List wallets
    let wallets = client.wallets.list_wallets(None).await?;
    println!("Found {} wallets", wallets.items.len());

    Ok(())
}

User Action Signing

Some operations (like creating wallets or signing transactions) require user action signing. The transport handles the challenge dance (/auth/action/init -> sign -> /auth/action) automatically; you provide the signing step by implementing the UserActionSigner trait with your credential's key material:

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,
    })?;

    // Operations requiring signatures will automatically sign
    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(())
}

Delegated Signing

In some setups your server talks to Dfns on behalf of a user, while the user keeps signing every request themselves (e.g. with a WebAuthn credential in a web app). DfnsDelegatedClient supports this: it needs no signer, and every operation that requires a user action signature is split into a <method>_init / <method>_complete pair.

  • <method>_init takes the request payload and returns the UserActionChallenge to be signed by the end user (typically in the browser).
  • <method>_complete takes the same payload, the challenge identifier, and the signed assertion, and performs the request.
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>> {
    // No signer needed, challenges are signed by the end user.
    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 with their credential and
    // returns the signed assertion to the server.
    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(())
}

Available Domains

The client provides access to the following API domains:

  • client.address_watches - Address watch operations (6 endpoints)
  • client.agreements - Agreement management (2 endpoints)
  • client.allocations - Allocation management (6 endpoints)
  • client.auth - Authentication and user management (58 endpoints)
  • client.exchanges - Exchange integrations (9 endpoints)
  • client.fee_sponsors - Fee sponsor management (7 endpoints)
  • client.keys - Key management (12 endpoints)
  • client.networks - Network information (7 endpoints)
  • client.payins - Payin operations (6 endpoints)
  • client.payouts - Payout operations (5 endpoints)
  • client.permissions - Permission management (8 endpoints)
  • client.policies - Policy management (8 endpoints)
  • client.signers - Signer management (17 endpoints)
  • client.staking - Staking operations (6 endpoints)
  • client.swaps - Token swap operations (5 endpoints)
  • client.vaults - Vault operations (15 endpoints)
  • client.wallets - Wallet operations (29 endpoints)
  • client.webhooks - Webhook subscriptions (8 endpoints)

Each domain provides typed methods for all available API endpoints.

Error Handling

All methods return Result<T, dfns_sdk_rust::Error>:

use dfns_sdk_rust::Error;

match client.wallets.get_wallet("invalid-wallet-id".to_string()).await {
    Ok(wallet) => println!("Wallet: {}", wallet.id),
    Err(Error::Api { status, body }) => {
        eprintln!("API error (status {}): {}", status, body.message);
    }
    Err(err) => eprintln!("Error: {}", err),
}

The Error enum covers API errors (decoded and raw), configuration errors, missing or failing signers, transport failures, and (de)serialization failures.

License

MIT License - See LICENSE file for details.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages