Rust SDK
The ACDC Rust SDK (acdc-sdk) provides type-safe, async-first access to the Alpha and Delta chains for Rust applications.
Installation
Add to your Cargo.toml:
[dependencies]
acdc-sdk = "0.1"
tokio = { version = "1", features = ["full"] }
Requirements:
- Rust 1.70+
- Tokio runtime
Quick Start
use acdc_sdk::{AcdcClient, Network};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to Delta mainnet
let client = AcdcClient::new(Network::DeltaMainnet)?;
// Get balance
let balance = client.get_balance("dx1abc123...").await?;
println!("Balance: {} ACDC", balance.formatted());
Ok(())
}
Client Configuration
Basic Setup
use acdc_sdk::{AcdcClient, Network};
// Predefined networks
let delta_mainnet = AcdcClient::new(Network::DeltaMainnet)?;
let delta_testnet = AcdcClient::new(Network::DeltaTestnet)?;
let alpha_mainnet = AcdcClient::new(Network::AlphaMainnet)?;
let alpha_testnet = AcdcClient::new(Network::AlphaTestnet)?;
Custom Configuration
use acdc_sdk::{AcdcClient, ClientConfig};
use std::time::Duration;
let config = ClientConfig::builder()
.rpc_url("https://custom-rpc.example.com")
.ws_url("wss://custom-ws.example.com")
.api_key("your-api-key")
.timeout(Duration::from_secs(30))
.retries(3)
.build()?;
let client = AcdcClient::with_config(config)?;
Environment Configuration
use acdc_sdk::AcdcClient;
// Reads from ACDC_RPC_URL, ACDC_WS_URL, ACDC_API_KEY
let client = AcdcClient::from_env()?;
Wallet Management
Creating Wallets
use acdc_sdk::{Wallet, Mnemonic};
// Generate new wallet
let wallet = Wallet::generate()?;
println!("Address: {}", wallet.address());
println!("Mnemonic: {}", wallet.mnemonic().unwrap());
// From mnemonic
let mnemonic = Mnemonic::parse("abandon abandon abandon ...")?;
let restored = Wallet::from_mnemonic(&mnemonic, None)?;
// With custom derivation path
let custom = Wallet::from_mnemonic(&mnemonic, Some("m/44'/60'/0'/0/5"))?;
// From private key
let imported = Wallet::from_private_key("0xprivatekey...")?;
Signing Transactions
use acdc_sdk::{Wallet, TransactionRequest};
let wallet = Wallet::from_private_key("0x...")?;
// Create and sign transaction
let tx = TransactionRequest::new()
.to("dx1recipient...".parse()?)
.value(parse_units("1.0", 18)?);
let signed_tx = wallet.sign_transaction(&tx).await?;
Querying Data
Account Information
use acdc_sdk::Address;
let address: Address = "dx1abc123...".parse()?;
// Get balance
let balance = client.get_balance(&address).await?;
println!("Balance: {} ACDC", balance.formatted());
println!("Raw: {} wei", balance.raw());
// Get nonce
let nonce = client.get_nonce(&address).await?;
// Get full account
let account = client.get_account(&address).await?;
println!("Nonce: {}", account.nonce);
println!("Balance: {}", account.balance);
Block Information
use acdc_sdk::BlockId;
// Latest block
let latest = client.get_block(BlockId::Latest).await?;
println!("Block {}: {}", latest.number, latest.hash);
// By number
let block = client.get_block(BlockId::Number(1234567)).await?;
// By hash
let block = client.get_block(BlockId::Hash("0xabc...".parse()?)).await?;
// With full transactions
let block_with_tx = client.get_block_with_txs(BlockId::Number(1234567)).await?;
for tx in &block_with_tx.transactions {
println!(" TX: {}", tx.hash);
}
Transaction Information
use acdc_sdk::TxHash;
let hash: TxHash = "0xtxhash...".parse()?;
// Get transaction
let tx = client.get_transaction(&hash).await?;
println!("From: {}", tx.from);
println!("To: {:?}", tx.to);
println!("Value: {}", format_units(tx.value, 18)?);
// Get receipt
let receipt = client.get_transaction_receipt(&hash).await?;
match receipt.status {
Some(1) => println!("Success"),
Some(0) => println!("Failed"),
None => println!("Pending"),
}
Sending Transactions
Simple Transfer
use acdc_sdk::{Wallet, TransactionRequest};
let wallet = Wallet::from_private_key("0x...")?;
let signer = wallet.connect(&client);
let tx = TransactionRequest::new()
.to("dx1recipient...".parse()?)
.value(parse_units("1.0", 18)?);
// Send and wait for confirmation
let pending_tx = signer.send_transaction(tx).await?;
let receipt = pending_tx.await?;
println!("Confirmed in block {}", receipt.block_number.unwrap());
Advanced Transaction Options
use acdc_sdk::{TransactionRequest, U256};
let tx = TransactionRequest::new()
.to("dx1recipient...".parse()?)
.value(parse_units("1.0", 18)?)
// Gas settings
.gas_limit(21000u64)
.gas_price(parse_units("10", 9)?) // 10 gwei
// Or EIP-1559
.max_fee_per_gas(parse_units("20", 9)?)
.max_priority_fee_per_gas(parse_units("2", 9)?)
// Manual nonce
.nonce(42u64)
// Contract data
.data(vec![0x12, 0x34, 0x56]);
let pending = signer.send_transaction(tx).await?;
Estimating Gas
let tx = TransactionRequest::new()
.from("dx1sender...".parse()?)
.to("dx1recipient...".parse()?)
.value(parse_units("1.0", 18)?);
let gas_estimate = client.estimate_gas(&tx).await?;
println!("Estimated gas: {}", gas_estimate);
Contract Interaction
Defining Contract Interface
use acdc_sdk::prelude::*;
// Generate type-safe bindings
abigen!(
ERC20,
r#"[
function balanceOf(address owner) view returns (uint256)
function transfer(address to, uint256 amount) returns (bool)
function approve(address spender, uint256 amount) returns (bool)
event Transfer(address indexed from, address indexed to, uint256 value)
]"#
);
Reading Contract State
let token_address: Address = "dx1tokencontract...".parse()?;
let token = ERC20::new(token_address, client.clone());
// Read balance
let balance = token.balance_of("dx1holder...".parse()?).call().await?;
println!("Balance: {}", format_units(balance, 18)?);
Writing to Contracts
let token = ERC20::new(token_address, signer.clone());
// Transfer tokens
let tx = token
.transfer("dx1recipient...".parse()?, parse_units("100", 18)?)
.send()
.await?;
let receipt = tx.await?;
println!("Transfer confirmed: {}", receipt.transaction_hash);
// Approve spending
let approve_tx = token
.approve("dx1spender...".parse()?, parse_units("1000", 18)?)
.send()
.await?;
approve_tx.await?;
Contract Events
use futures::StreamExt;
// Subscribe to Transfer events
let filter = token.transfer_filter();
let mut stream = filter.subscribe().await?;
while let Some(event) = stream.next().await {
match event {
Ok(log) => {
println!("Transfer: {} -> {}: {}",
log.from, log.to, format_units(log.value, 18)?);
}
Err(e) => eprintln!("Error: {}", e),
}
}
// Query historical events
let events = token
.transfer_filter()
.from_block(1234567)
.to_block(1234667)
.query()
.await?;
for event in events {
println!("Historical transfer: {:?}", event);
}
WebSocket Subscriptions
Block Subscriptions
use futures::StreamExt;
// Subscribe to new blocks
let mut block_stream = client.subscribe_blocks().await?;
while let Some(block) = block_stream.next().await {
println!("New block: {}", block.number);
}
Transaction Subscriptions
// Subscribe to pending transactions
let mut tx_stream = client.subscribe_pending_txs().await?;
while let Some(tx_hash) = tx_stream.next().await {
println!("Pending TX: {}", tx_hash);
}
Log Subscriptions
use acdc_sdk::Filter;
// Subscribe to contract events
let filter = Filter::new()
.address("dx1contract...".parse()?)
.topic0("0xevent_signature...".parse()?);
let mut log_stream = client.subscribe_logs(&filter).await?;
while let Some(log) = log_stream.next().await {
println!("Log: {:?}", log);
}
Staking Module
use acdc_sdk::staking::StakingClient;
let staking = StakingClient::new(signer.clone());
// Delegate stake
let delegate_tx = staking
.delegate("dx1validator...".parse()?, parse_units("1000", 18)?)
.send()
.await?;
delegate_tx.await?;
// Get stake info
let stake_info = staking.get_stake(&signer.address()).await?;
println!("Staked: {} ACDC", format_units(stake_info.amount, 18)?);
println!("Rewards: {} ACDC", format_units(stake_info.rewards, 18)?);
// Claim rewards
let claim_tx = staking.claim_rewards().send().await?;
claim_tx.await?;
// Unstake
let unstake_tx = staking
.unstake(parse_units("500", 18)?)
.send()
.await?;
unstake_tx.await?;
Governance Module
use acdc_sdk::governance::{GovernanceClient, Vote};
let governance = GovernanceClient::new(signer.clone());
// Get proposals
let proposals = governance.get_proposals(None).await?;
for proposal in &proposals {
println!("#{}: {}", proposal.id, proposal.title);
}
// Vote on proposal
let vote_tx = governance
.vote(42, Vote::Yes)
.send()
.await?;
vote_tx.await?;
Alpha Chain (Privacy)
use acdc_sdk::alpha::{AlphaClient, ViewKey};
let alpha = AlphaClient::new(Network::AlphaMainnet)?;
// Generate view key
let view_key = ViewKey::from_private_key(&wallet.private_key())?;
// Scan for records
let records = alpha.scan_records(&view_key).await?;
for record in &records {
println!("Record: {}", record.commitment);
println!(" Value: {}", format_units(record.value, 18)?);
}
// Create private transfer
let private_tx = alpha.create_private_transfer(
&wallet,
"ax1recipient...".parse()?,
parse_units("10", 18)?,
&records[..2], // Input records
).await?;
// Submit
let hash = alpha.submit_transaction(private_tx).await?;
println!("TX Hash: {}", hash);
Utility Functions
Unit Conversion
use acdc_sdk::{parse_units, format_units, parse_acdc, format_acdc};
// Generic conversion
let wei = parse_units("1.5", 18)?; // U256
let eth = format_units(wei, 18)?; // "1.5"
// ACDC-specific
let acdc_wei = parse_acdc("1.5")?; // U256
let acdc = format_acdc(acdc_wei)?; // "1.5"
Address Utilities
use acdc_sdk::{Address, Chain};
let address: Address = "dx1abc...".parse()?;
// Validate
assert!(address.is_valid());
// Get chain
assert_eq!(address.chain(), Chain::Delta);
// Checksum
let checksummed = address.to_checksum();
Cryptography
use acdc_sdk::crypto::{keccak256, sign_message, recover_signer};
// Hash
let hash = keccak256(b"data");
// Sign message
let signature = wallet.sign_message("Hello ACDC").await?;
// Recover signer
let signer = recover_signer("Hello ACDC", &signature)?;
assert_eq!(signer, wallet.address());
Error Handling
use acdc_sdk::{AcdcError, RpcError};
match client.get_balance(&address).await {
Ok(balance) => println!("Balance: {}", balance),
Err(AcdcError::Rpc(RpcError { code, message, .. })) => {
eprintln!("RPC error {}: {}", code, message);
}
Err(AcdcError::Network(e)) => {
eprintln!("Network error: {}", e);
}
Err(e) => {
eprintln!("Other error: {}", e);
}
}
Error Types
| Error | Description |
|---|---|
AcdcError::Rpc | JSON-RPC error from node |
AcdcError::Network | Connection/timeout error |
AcdcError::InvalidAddress | Invalid address format |
AcdcError::InsufficientFunds | Not enough balance |
AcdcError::Signature | Signature error |
AcdcError::Abi | ABI encoding/decoding error |
Async Runtime
The SDK is designed for Tokio but can work with other runtimes:
// With Tokio (recommended)
#[tokio::main]
async fn main() {
let client = AcdcClient::new(Network::DeltaMainnet).unwrap();
// ...
}
// With async-std
#[async_std::main]
async fn main() {
let client = AcdcClient::builder()
.network(Network::DeltaMainnet)
.runtime(Runtime::AsyncStd)
.build()
.unwrap();
// ...
}
Feature Flags
[dependencies]
acdc-sdk = { version = "0.1", features = ["full"] }
# Available features:
# - "ws" - WebSocket support (default)
# - "staking" - Staking module
# - "governance" - Governance module
# - "alpha" - Alpha chain support
# - "full" - All features