Skip to main content

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

ErrorDescription
AcdcError::RpcJSON-RPC error from node
AcdcError::NetworkConnection/timeout error
AcdcError::InvalidAddressInvalid address format
AcdcError::InsufficientFundsNot enough balance
AcdcError::SignatureSignature error
AcdcError::AbiABI 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