Welcome, builders. This repo holds the Dfns Rust SDK. Useful links:
cargo add dfns-sdk-rustuse 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(())
}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(())
}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>_inittakes the request payload and returns theUserActionChallengeto be signed by the end user (typically in the browser).<method>_completetakes 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(())
}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.
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.
MIT License - See LICENSE file for details.