🚀 Rust SDK
Build high-performance blockchain applications with Cedra's native Rust SDK. Designed for system-level integrations, the SDK provides zero-cost abstractions and compile-time safety for production blockchain development. Whether you're building trading bots, validator tools, or infrastructure services, Rust gives you the performance and reliability you need.
Start Building in Minutes
use cedra_sdk::{Client, LocalAccount};
// That's it! You're ready to build on Cedra
let client = Client::new("https://testnet.cedra.dev");
let account = LocalAccount::generate(&mut rand::rngs::OsRng);
Ready to dive deeper? Let's explore what makes the Rust SDK powerful.
📦 Installation
Add the Cedra SDK to your Rust project by updating your Cargo.toml:
[dependencies]
cedra-sdk = { git = "https://github.com/cedra-labs/cedra-network", branch = "testnet" }
[patch.crates-io]
merlin = { git = "https://github.com/cedra-labs/merlin" }
Create a .cargo/config.toml file in your project root:
[build]
rustflags = ["--cfg", "tokio_unstable"]
For production applications, pin to specific commit hashes to ensure reproducible builds:
cedra-sdk = { git = "https://github.com/cedra-labs/cedra-network", rev = "abc123..." }
🎯 Your First Transaction
This complete example walks you through a typical token transfer workflow on Cedra:
- Account Generation - Create two new accounts with cryptographic keypairs
- Faucet Integration - Fund Alice's account with testnet tokens
- Balance Queries - Check account balances at each step
- Token Transfers - Send tokens between accounts with automatic gas handling
- Transaction Confirmation - Wait for transactions to finalize on-chain
use anyhow::{Context, Result};
use cedra_sdk::{
coin_client::CoinClient,
rest_client::{Client, FaucetClient},
types::LocalAccount,
};
use std::{str::FromStr, sync::LazyLock};
use url::Url;
static NODE_URL: LazyLock<Url> = LazyLock::new(|| {
Url::from_str(
std::env::var("CEDRA_NODE_URL")
.as_ref()
.map(|s| s.as_str())
.unwrap_or("https://testnet.cedra.dev"),
)
.unwrap()
});
static FAUCET_URL: LazyLock<Url> = LazyLock::new(|| {
Url::from_str(
std::env::var("CEDRA_FAUCET_URL")
.as_ref()
.map(|s| s.as_str())
.unwrap_or("https://faucet-api.cedra.dev"),
)
.unwrap()
});
#[tokio::main]
async fn main() -> Result<()> {
let rest_client = Client::new(NODE_URL.clone());
let faucet_client = FaucetClient::new(FAUCET_URL.clone(), NODE_URL.clone());
let coin_client = CoinClient::new(&rest_client);
let mut alice = LocalAccount::generate(&mut rand::rngs::OsRng);
let bob = LocalAccount::generate(&mut rand::rngs::OsRng);
// Print account addresses.
println!("\n=== Addresses ===");
println!("Alice: {}", alice.address().to_hex_literal());
println!("Bob: {}", bob.address().to_hex_literal());
// Create the accounts on chain, but only fund Alice.
faucet_client
.fund(alice.address(), 100_000_000)
.await
.context("Failed to fund Alice's account")?;
faucet_client
.create_account(bob.address())
.await
.context("Failed to create Bob's account")?;
// Print initial balances.
println!("\n=== Initial Balances ===");
println!(
"Alice: {:?}",
coin_client
.get_account_balance(&alice.address())
.await
.context("Failed to get Alice's account balance")?
);
println!(
"Bob: {:?}",
coin_client
.get_account_balance(&bob.address())
.await
.context("Failed to get Bob's account balance")?
);
// Have Alice send Bob some coins.
let txn_hash = coin_client
.transfer(&mut alice, bob.address(), 1_000, None)
.await
.context("Failed to submit transaction to transfer coins")?;
rest_client
.wait_for_transaction(&txn_hash)
.await
.context("Failed when waiting for the transfer transaction")?;
// Print intermediate balances.
println!("\n=== Intermediate Balances ===");
println!(
"Alice: {:?}",
coin_client
.get_account_balance(&alice.address())
.await
.context("Failed to get Alice's account balance the second time")?
);
println!(
"Bob: {:?}",
coin_client
.get_account_balance(&bob.address())
.await
.context("Failed to get Bob's account balance the second time")?
);
// Have Alice send Bob some more coins.
let txn_hash = coin_client
.transfer(&mut alice, bob.address(), 1_000, None)
.await
.context("Failed to submit transaction to transfer coins")?;
rest_client
.wait_for_transaction(&txn_hash)
.await
.context("Failed when waiting for the transfer transaction")?;
// Print final balances.
println!("\n=== Final Balances ===");
println!(
"Alice: {:?}",
coin_client
.get_account_balance(&alice.address())
.await
.context("Failed to get Alice's account balance the third time")?
);
println!(
"Bob: {:?}",
coin_client
.get_account_balance(&bob.address())
.await
.context("Failed to get Bob's account balance the third time")?
);
Ok(())
}
That's it! The SDK handles all the complexity - sequence numbers, gas estimation, signing, and confirmation. Notice how Rust's type system ensures you can't make mistakes like sending to an invalid address or using the wrong amount format.
While our TypeScript SDK is perfect for web applications, the Rust SDK is your choice when performance and reliability are non-negotiable.
🚀 Next Steps
Now that you've set up the SDK and sent your first transaction, here's your path to mastering Cedra development with Rust:
Core SDK Features
- Account Management - Generate wallets, manage keys, and work with account resources
- Transaction Guide - Build complex transactions, handle gas estimation, and understand the transaction lifecycle
Build Real Applications
- First Fungible Asset - Create your own token with Move
- NFT Contract Guide - Build a complete NFT collection
- Build a DEX - Learn DeFi development on Cedra
Expand Your Knowledge
- Move Programming - Master smart contract development
- CLI Reference - Deploy and test your contracts
- TypeScript SDK - Build web frontends for your dApps