Skip to main content

Rust SDK Advanced Setup Guide

This comprehensive guide covers professional Rust development setup for Saros SDK applications, including workspace configuration, dependency management, and production deployment patterns.

Development Environment Setup​

1. Rust Toolchain Configuration​

# Install latest stable Rust with component support
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

# Install required components
rustup component add clippy rust-analyzer rust-src rustfmt
rustup target add wasm32-unknown-unknown

# Install development tools
cargo install cargo-watch cargo-expand cargo-edit cargo-audit cargo-outdated
cargo install solana-cli anchor-cli

# Verify installation
rustc --version && cargo --version && solana --version

2. IDE Configuration​

VS Code Setup​

// .vscode/settings.json
{
"rust-analyzer.checkOnSave.command": "clippy",
"rust-analyzer.cargo.features": "all",
"rust-analyzer.procMacro.enable": true,
"rust-analyzer.imports.granularity.group": "module",
"editor.formatOnSave": true,
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}

VS Code Extensions​

// .vscode/extensions.json
{
"recommendations": [
"rust-lang.rust-analyzer",
"serayuzgur.crates",
"vadimcn.vscode-lldb",
"ms-vscode.test-adapter-converter",
"usernamehw.errorlens"
]
}

Cargo Workspace Configuration​

1. Multi-Package Workspace​

# Cargo.toml (workspace root)
[workspace]
resolver = "2"
members = [
"crates/trading-bot",
"crates/analytics-engine",
"crates/risk-management",
"crates/shared-types",
"examples/*"
]

# Shared dependencies across workspace
[workspace.dependencies]
saros-dlmm-sdk-rs = "0.1.0"
solana-sdk = "1.18.0"
solana-client = "1.18.0"
solana-program = "1.18.0"
anchor-lang = "0.29.0"
anchor-spl = "0.29.0"
spl-token = "4.0.0"
spl-associated-token-account = "2.3.0"
tokio = { version = "1.0", features = ["full", "tracing"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
thiserror = "1.0"
log = "0.4"
env_logger = "0.10"
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "1.0", features = ["v4", "serde"] }
dashmap = "5.5"
once_cell = "1.19"
async-trait = "0.1"
futures = "0.3"
crossbeam-channel = "0.5"
parking_lot = "0.12"
rayon = "1.8"
rand = "0.8"

# Development dependencies
[workspace.dev-dependencies]
tokio-test = "0.4"
criterion = "0.5"
proptest = "1.4"
mockall = "0.12"
tempfile = "3.8"
test-log = "0.2"

# Workspace lints and settings
[workspace.lints.rust]
unsafe_code = "forbid"
unused_extern_crates = "warn"
unused_import_braces = "warn"
unused_qualifications = "warn"

[workspace.lints.clippy]
all = "warn"
pedantic = "warn"
nursery = "warn"
cargo = "warn"
# Allow some pedantic lints that are too strict
module_name_repetitions = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"

2. Trading Bot Crate Configuration​

# crates/trading-bot/Cargo.toml
[package]
name = "saros-trading-bot"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <your.email@example.com>"]
description = "High-performance DLMM trading bot using Saros SDK"
repository = "https://github.com/your-org/saros-trading-bot"
license = "MIT OR Apache-2.0"
keywords = ["solana", "dlmm", "trading", "defi", "saros"]
categories = ["finance", "cryptocurrency"]

[dependencies]
# Workspace dependencies
saros-dlmm-sdk-rs = { workspace = true }
solana-sdk = { workspace = true }
solana-client = { workspace = true }
tokio = { workspace = true }
serde = { workspace = true }
anyhow = { workspace = true }
log = { workspace = true }
tracing = { workspace = true }
chrono = { workspace = true }
uuid = { workspace = true }

# Additional dependencies for trading
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
tungstenite = "0.20"
tokio-tungstenite = "0.20"
ta = "0.5" # Technical analysis
rust_decimal = { version = "1.32", features = ["serde-float"] }

# Performance dependencies
ahash = "0.8"
smallvec = { version = "1.11", features = ["serde"] }
bytes = "1.5"

[dev-dependencies]
tokio-test = { workspace = true }
criterion = { workspace = true }
tempfile = { workspace = true }

# Build configuration for performance
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true

[profile.dev]
opt-level = 1
debug = true
split-debuginfo = "unpacked"

# Benchmark profile
[profile.bench]
inherits = "release"
debug = true

[[bin]]
name = "trading-bot"
path = "src/main.rs"

[[bench]]
name = "trading_benchmarks"
harness = false

3. Shared Types Crate​

# crates/shared-types/Cargo.toml
[package]
name = "saros-shared-types"
version = "0.1.0"
edition = "2021"
description = "Shared types and utilities for Saros applications"

[dependencies]
serde = { workspace = true }
solana-sdk = { workspace = true }
chrono = { workspace = true }
uuid = { workspace = true }
thiserror = { workspace = true }
anchor-lang = { workspace = true }

[features]
default = ["std"]
std = []
no-std = []

Development Configuration Files​

1. Clippy Configuration​

# .clippy.toml
avoid-breaking-exported-api = false
msrv = "1.70.0"
cognitive-complexity-threshold = 30
type-complexity-threshold = 60
too-many-arguments-threshold = 8
enum-variant-names-threshold = 4
single-char-lifetime-names-threshold = 4

2. Rustfmt Configuration​

# rustfmt.toml
max_width = 100
hard_tabs = false
tab_spaces = 4
newline_style = "Unix"
use_small_heuristics = "Default"
reorder_imports = true
reorder_modules = true
remove_nested_parens = true
edition = "2021"
merge_derives = true
use_try_shorthand = true
use_field_init_shorthand = true
force_explicit_abi = true
condense_wildcard_suffixes = true
color = "Auto"
unstable_features = true
format_code_in_doc_comments = true
wrap_comments = true
comment_width = 80
normalize_comments = true
normalize_doc_attributes = true

3. Development Scripts​

# Create .cargo/config.toml for custom commands
[alias]
xtask = "run --manifest-path xtask/Cargo.toml --"
check-all = "clippy --workspace --all-targets --all-features -- -D warnings"
test-all = "test --workspace --all-features"
doc-all = "doc --workspace --all-features --no-deps"
build-release = "build --workspace --release"
fmt-all = "fmt --all -- --check"
audit = "audit --deny warnings"
outdated = "outdated --workspace"

# Environment variables for development
[env]
RUST_LOG = { value = "debug", relative = true }
RUST_BACKTRACE = { value = "1", relative = true }

Performance Optimization Configuration​

1. Cargo Build Optimization​

# Cargo.toml optimization settings
[profile.release]
opt-level = 3 # Maximum optimization
lto = "fat" # Link Time Optimization
codegen-units = 1 # Better optimization
rpath = false
debug = false
debug-assertions = false
overflow-checks = false
panic = "abort" # Smaller binary size
incremental = false # Better for release builds
strip = "symbols" # Remove debug symbols

# Custom profile for high-frequency trading
[profile.hft]
inherits = "release"
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
strip = "symbols"
# Enable aggressive optimizations
overflow-checks = false
debug-assertions = false

# Development profile optimized for fast compilation
[profile.dev]
opt-level = 1 # Basic optimization for better debug experience
debug = true
split-debuginfo = "unpacked"
incremental = true
codegen-units = 256 # Faster compilation

2. Target-Specific Configuration​

# .cargo/config.toml
[build]
target-dir = "target"

# Linux optimizations
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-C", "target-cpu=native",
"-C", "link-arg=-fuse-ld=lld",
]

# macOS optimizations
[target.x86_64-apple-darwin]
rustflags = [
"-C", "target-cpu=native",
]

# Windows optimizations
[target.x86_64-pc-windows-msvc]
rustflags = [
"-C", "target-cpu=native",
]

Testing Infrastructure​

1. Comprehensive Test Configuration​

// tests/common/mod.rs
use anyhow::Result;
use once_cell::sync::Lazy;
use solana_sdk::{pubkey::Pubkey, signature::Keypair};
use std::sync::Arc;
use tokio::sync::Mutex;

pub static TEST_CONFIG: Lazy<TestConfig> = Lazy::new(|| {
TestConfig::new().expect("Failed to initialize test config")
});

pub static TEST_CLIENT: Lazy<Arc<Mutex<TestDlmmClient>>> = Lazy::new(|| {
Arc::new(Mutex::new(
TestDlmmClient::new(&TEST_CONFIG).expect("Failed to create test client")
))
});

#[derive(Debug, Clone)]
pub struct TestConfig {
pub rpc_url: String,
pub program_id: Pubkey,
pub test_pool: Pubkey,
pub test_tokens: TestTokens,
pub test_wallet: Keypair,
}

#[derive(Debug, Clone)]
pub struct TestTokens {
pub mint_x: Pubkey,
pub mint_y: Pubkey,
pub decimals_x: u8,
pub decimals_y: u8,
}

impl TestConfig {
pub fn new() -> Result<Self> {
Ok(TestConfig {
rpc_url: std::env::var("TEST_RPC_URL")
.unwrap_or_else(|_| "https://api.devnet.solana.com".to_string()),
program_id: "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo".parse()?,
test_pool: "5BHZkcKobCXvuzKsMqZiPjYmhA2KGjvNJ9Xp6sF8KP8x".parse()?,
test_tokens: TestTokens {
mint_x: "So11111111111111111111111111111111111111112".parse()?, // WSOL
mint_y: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".parse()?, // USDC
decimals_x: 9,
decimals_y: 6,
},
test_wallet: Keypair::new(),
})
}
}

pub struct TestDlmmClient {
// Test client implementation
}

impl TestDlmmClient {
pub fn new(_config: &TestConfig) -> Result<Self> {
Ok(Self {})
}
}

2. Integration Test Suite​

// tests/integration_tests.rs
use anyhow::Result;
use saros_dlmm_sdk_rs::*;
use serial_test::serial;
use test_log::test;
use tokio::time::{timeout, Duration};

mod common;
use common::*;

#[test(tokio::test)]
#[serial]
async fn test_full_trading_workflow() -> Result<()> {
let config = &*TEST_CONFIG;
let client = TEST_CLIENT.lock().await;

// Test complete workflow: create position -> monitor -> close
timeout(Duration::from_secs(30), async {
// Load test pool
let pool = client.load_pool(config.test_pool).await?;
assert_eq!(pool.token_x_mint, config.test_tokens.mint_x);

// Create position with 0.1% range
let position_params = create_test_position_params(&pool)?;
let position = client.create_position(config.test_pool, position_params).await?;

// Monitor position for 5 seconds
tokio::time::sleep(Duration::from_secs(5)).await;

let updated_position = client.refresh_position(&position.address).await?;
assert!(updated_position.liquidity_x > 0 || updated_position.liquidity_y > 0);

// Close position
let close_result = client.close_position(&position.address).await?;
assert!(close_result.success);

Ok::<(), anyhow::Error>(())
}).await??;

Ok(())
}

#[test(tokio::test)]
async fn test_error_handling() -> Result<()> {
let client = TEST_CLIENT.lock().await;

// Test invalid pool address
let invalid_pool = Pubkey::new_unique();
let result = client.load_pool(invalid_pool).await;
assert!(result.is_err());

// Test invalid position
let invalid_position = Pubkey::new_unique();
let result = client.refresh_position(&invalid_position).await;
assert!(result.is_err());

Ok(())
}

fn create_test_position_params(pool: &DlmmPool) -> Result<PositionParams> {
let current_price = pool.get_current_price()?;
let range = 0.001; // 0.1% range

Ok(PositionParams {
bin_range: BinRange {
lower_bin: pool.price_to_bin_id(current_price * (1.0 - range))?,
upper_bin: pool.price_to_bin_id(current_price * (1.0 + range))?,
},
amount_x: 100_000, // 0.0001 SOL
amount_y: 100, // 0.0001 USDC
distribution: AmountDistribution::Balanced,
})
}

Production Configuration​

1. Environment Management​

// src/config/mod.rs
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use solana_sdk::{pubkey::Pubkey, signature::Keypair};
use std::{env, fs, str::FromStr};
use tracing::info;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProductionConfig {
pub environment: Environment,
pub solana: SolanaConfig,
pub trading: TradingConfig,
pub monitoring: MonitoringConfig,
pub security: SecurityConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Environment {
Development,
Staging,
Production,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SolanaConfig {
pub rpc_url: String,
pub ws_url: Option<String>,
pub commitment: String,
pub timeout_seconds: u64,
pub max_retries: u32,
pub dlmm_program_id: String,
pub jupiter_program_id: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TradingConfig {
pub max_position_size: f64,
pub default_slippage: f64,
pub max_daily_volume: f64,
pub risk_limits: RiskLimits,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiskLimits {
pub max_drawdown_percent: f64,
pub max_positions: u32,
pub max_exposure_per_pool: f64,
pub stop_loss_threshold: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MonitoringConfig {
pub enable_metrics: bool,
pub metrics_port: u16,
pub log_level: String,
pub alert_endpoints: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
pub enable_rate_limiting: bool,
pub max_requests_per_minute: u32,
pub require_signature_verification: bool,
pub allowed_programs: Vec<String>,
}

impl ProductionConfig {
pub fn load() -> Result<Self> {
let env = env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string());

let config_path = match env.as_str() {
"production" => "config/production.toml",
"staging" => "config/staging.toml",
_ => "config/development.toml",
};

let config_content = fs::read_to_string(config_path)
.map_err(|e| anyhow!("Failed to read config file {}: {}", config_path, e))?;

let mut config: ProductionConfig = toml::from_str(&config_content)
.map_err(|e| anyhow!("Failed to parse config file: {}", e))?;

// Override with environment variables if set
config.override_with_env()?;

info!("Loaded configuration for environment: {:?}", config.environment);
Ok(config)
}

fn override_with_env(&mut self) -> Result<()> {
if let Ok(rpc_url) = env::var("SOLANA_RPC_URL") {
self.solana.rpc_url = rpc_url;
}

if let Ok(log_level) = env::var("RUST_LOG") {
self.monitoring.log_level = log_level;
}

if let Ok(max_positions) = env::var("MAX_POSITIONS") {
self.trading.risk_limits.max_positions = max_positions.parse()?;
}

Ok(())
}

pub fn dlmm_program_id(&self) -> Result<Pubkey> {
Pubkey::from_str(&self.solana.dlmm_program_id)
.map_err(|e| anyhow!("Invalid DLMM program ID: {}", e))
}

pub fn jupiter_program_id(&self) -> Result<Pubkey> {
Pubkey::from_str(&self.solana.jupiter_program_id)
.map_err(|e| anyhow!("Invalid Jupiter program ID: {}", e))
}
}

2. Configuration Files​

# config/production.toml
environment = "Production"

[solana]
rpc_url = "https://api.mainnet-beta.solana.com"
ws_url = "wss://api.mainnet-beta.solana.com"
commitment = "confirmed"
timeout_seconds = 30
max_retries = 3
dlmm_program_id = "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo"
jupiter_program_id = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"

[trading]
max_position_size = 1000000.0 # $1M max position
default_slippage = 0.005 # 0.5%
max_daily_volume = 10000000.0 # $10M daily limit

[trading.risk_limits]
max_drawdown_percent = 5.0 # 5% max drawdown
max_positions = 50 # Maximum 50 concurrent positions
max_exposure_per_pool = 100000.0 # $100K max per pool
stop_loss_threshold = 2.0 # 2% stop loss

[monitoring]
enable_metrics = true
metrics_port = 9090
log_level = "info"
alert_endpoints = ["https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"]

[security]
enable_rate_limiting = true
max_requests_per_minute = 1000
require_signature_verification = true
allowed_programs = [
"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"
]
# config/development.toml
environment = "Development"

[solana]
rpc_url = "https://api.devnet.solana.com"
ws_url = "wss://api.devnet.solana.com"
commitment = "processed"
timeout_seconds = 10
max_retries = 5
dlmm_program_id = "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo"
jupiter_program_id = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"

[trading]
max_position_size = 1000.0 # $1K max for testing
default_slippage = 0.01 # 1%
max_daily_volume = 10000.0 # $10K daily limit

[trading.risk_limits]
max_drawdown_percent = 10.0
max_positions = 5
max_exposure_per_pool = 500.0
stop_loss_threshold = 5.0

[monitoring]
enable_metrics = true
metrics_port = 3001
log_level = "debug"
alert_endpoints = []

[security]
enable_rate_limiting = false
max_requests_per_minute = 10000
require_signature_verification = false
allowed_programs = [
"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"
]

Continuous Integration Setup​

1. GitHub Actions Configuration​

# .github/workflows/rust-ci.yml
name: Rust CI

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]

env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1

jobs:
test:
name: Test Suite
runs-on: ubuntu-latest
strategy:
matrix:
rust: [stable, beta, nightly]

steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
components: clippy, rustfmt

- name: Cache cargo registry
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }}

- name: Check formatting
run: cargo fmt --all -- --check

- name: Run clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings

- name: Run tests
run: cargo test --workspace --all-features --verbose

- name: Run integration tests
run: cargo test --workspace --test integration_tests
env:
TEST_RPC_URL: https://api.devnet.solana.com

- name: Security audit
run: |
cargo install cargo-audit
cargo audit

- name: Check dependencies
run: |
cargo install cargo-outdated
cargo outdated --exit-code 1

benchmark:
name: Performance Benchmarks
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Run benchmarks
run: cargo bench --workspace

- name: Upload benchmark results
uses: benchmark-action/github-action-benchmark@v1
with:
tool: 'cargo'
output-file-path: target/criterion/*/base/benchmark.json

security:
name: Security Scan
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Security audit
run: |
cargo install cargo-audit
cargo audit --deny warnings

- name: Dependency check
run: |
cargo install cargo-deny
cargo deny check

2. Pre-commit Hooks​

# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files

- repo: local
hooks:
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt --all --
language: system
types: [rust]
pass_filenames: false

- id: cargo-clippy
name: cargo clippy
entry: cargo clippy --workspace --all-targets --all-features -- -D warnings
language: system
types: [rust]
pass_filenames: false

- id: cargo-test
name: cargo test
entry: cargo test --workspace --all-features
language: system
types: [rust]
pass_filenames: false

Advanced Dependency Management​

1. Feature Gates Configuration​

# Cargo.toml features for conditional compilation
[features]
default = ["std", "devnet"]
std = []
no-std = ["heapless", "nb"]

# Network features
mainnet = []
devnet = []
testnet = []
localnet = []

# Performance features
simd = ["wide"]
parallel = ["rayon"]
async = ["tokio"]

# Monitoring features
metrics = ["prometheus", "opentelemetry"]
tracing = ["tracing-subscriber", "tracing-opentelemetry"]
profiling = ["pprof", "jemallocator"]

# Security features
secure = ["ring", "rustls"]
audit = ["cargo-audit"]

# Development features
mock = ["mockall"]
fuzzing = ["arbitrary"]
testing = ["proptest", "quickcheck"]

2. Dependency Pinning Strategy​

# Use specific versions for critical dependencies
[dependencies]
saros-dlmm-sdk-rs = "=0.1.0" # Pin exact version
solana-sdk = "~1.18.0" # Allow patch updates only
anchor-lang = "^0.29.0" # Allow minor updates
tokio = "1.35" # Pin major.minor

# Development dependencies can be more flexible
[dev-dependencies]
criterion = "*" # Latest for benchmarks
proptest = "1" # Major version only

Docker Configuration​

1. Multi-stage Dockerfile​

# Dockerfile
# Build stage
FROM rust:1.75-slim as builder

WORKDIR /app

# Install dependencies for building
RUN apt-get update && apt-get install -y \
pkg-config \
libssl-dev \
protobuf-compiler \
&& rm -rf /var/lib/apt/lists/*

# Copy dependency files first for better caching
COPY Cargo.toml Cargo.lock ./
COPY crates/*/Cargo.toml ./crates/

# Build dependencies (cached layer)
RUN mkdir -p src && echo "fn main() {}" > src/main.rs
RUN cargo build --release --locked
RUN rm -rf src

# Copy source code and build
COPY . .
RUN cargo build --release --locked

# Runtime stage
FROM debian:bookworm-slim

WORKDIR /app

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
libssl3 \
&& rm -rf /var/lib/apt/lists/*

# Copy binary from builder
COPY --from=builder /app/target/release/trading-bot /usr/local/bin/trading-bot

# Create non-root user
RUN useradd -r -s /bin/false trading-bot
USER trading-bot

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD trading-bot --health-check || exit 1

EXPOSE 9090

CMD ["trading-bot"]

2. Docker Compose for Development​

# docker-compose.yml
version: '3.8'

services:
trading-bot:
build:
context: .
dockerfile: Dockerfile
target: builder # Use builder stage for development
volumes:
- .:/app
- cargo-cache:/usr/local/cargo/registry
- target-cache:/app/target
environment:
- RUST_ENV=development
- RUST_LOG=debug
- SOLANA_RPC_URL=https://api.devnet.solana.com
ports:
- "9090:9090" # Metrics port
- "3001:3001" # Debug port
command: cargo watch -x 'run --bin trading-bot'

prometheus:
image: prom/prometheus:latest
ports:
- "9091:9090"
volumes:
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml

grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-storage:/var/lib/grafana

volumes:
cargo-cache:
target-cache:
grafana-storage:

Monitoring and Observability​

1. Metrics Configuration​

# Add to main Cargo.toml
[dependencies]
prometheus = "0.13"
opentelemetry = "0.21"
opentelemetry-prometheus = "0.14"
tracing-opentelemetry = "0.22"

2. Metrics Implementation​

// src/monitoring/mod.rs
use prometheus::{Counter, Gauge, Histogram, IntCounterVec, Registry};
use once_cell::sync::Lazy;
use std::time::Duration;

pub static METRICS: Lazy<Metrics> = Lazy::new(Metrics::new);

pub struct Metrics {
pub transactions_total: IntCounterVec,
pub active_positions: Gauge,
pub pnl_realized: Counter,
pub execution_time: Histogram,
pub registry: Registry,
}

impl Metrics {
fn new() -> Self {
let registry = Registry::new();

let transactions_total = IntCounterVec::new(
prometheus::Opts::new("transactions_total", "Total number of transactions"),
&["type", "status"]
).unwrap();

let active_positions = Gauge::new(
"active_positions", "Number of active trading positions"
).unwrap();

let pnl_realized = Counter::new(
"pnl_realized_total", "Total realized profit and loss"
).unwrap();

let execution_time = Histogram::with_opts(
prometheus::HistogramOpts::new("execution_time_seconds", "Transaction execution time")
.buckets(vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0])
).unwrap();

registry.register(Box::new(transactions_total.clone())).unwrap();
registry.register(Box::new(active_positions.clone())).unwrap();
registry.register(Box::new(pnl_realized.clone())).unwrap();
registry.register(Box::new(execution_time.clone())).unwrap();

Self {
transactions_total,
active_positions,
pnl_realized,
execution_time,
registry,
}
}

pub fn start_metrics_server(port: u16) -> Result<()> {
use prometheus::{Encoder, TextEncoder};
use std::net::SocketAddr;
use warp::Filter;

let metrics_route = warp::path("metrics")
.map(|| {
let encoder = TextEncoder::new();
let metric_families = METRICS.registry.gather();
let mut buffer = Vec::new();
encoder.encode(&metric_families, &mut buffer).unwrap();
String::from_utf8(buffer).unwrap()
});

let addr: SocketAddr = ([0, 0, 0, 0], port).into();

tokio::spawn(async move {
warp::serve(metrics_route).run(addr).await;
});

log::info!("Metrics server started on port {}", port);
Ok(())
}
}

Security Configuration​

1. Secrets Management​

// src/security/secrets.rs
use anyhow::{anyhow, Result};
use serde::Deserialize;
use solana_sdk::signature::Keypair;
use std::{env, fs, path::Path};
use zeroize::{Zeroize, ZeroizeOnDrop};

#[derive(Debug, Zeroize, ZeroizeOnDrop)]
pub struct SecretManager {
wallet_keypair: Vec<u8>,
api_keys: std::collections::HashMap<String, String>,
}

impl SecretManager {
pub fn load() -> Result<Self> {
let mut secret_manager = Self {
wallet_keypair: Vec::new(),
api_keys: std::collections::HashMap::new(),
};

// Load wallet from secure location
if let Ok(wallet_path) = env::var("WALLET_KEYPAIR_PATH") {
let keypair_bytes = fs::read(&wallet_path)
.map_err(|e| anyhow!("Failed to read wallet file {}: {}", wallet_path, e))?;
secret_manager.wallet_keypair = keypair_bytes;
}

// Load API keys from environment
for (key, value) in env::vars() {
if key.starts_with("API_KEY_") {
secret_manager.api_keys.insert(key, value);
}
}

Ok(secret_manager)
}

pub fn get_wallet_keypair(&self) -> Result<Keypair> {
if self.wallet_keypair.is_empty() {
return Err(anyhow!("No wallet keypair loaded"));
}

Keypair::from_bytes(&self.wallet_keypair)
.map_err(|e| anyhow!("Invalid wallet keypair: {}", e))
}

pub fn get_api_key(&self, service: &str) -> Option<&str> {
let key = format!("API_KEY_{}", service.to_uppercase());
self.api_keys.get(&key).map(|s| s.as_str())
}
}

// Secure configuration loading
#[derive(Deserialize)]
pub struct SecureConfig {
#[serde(skip)]
pub wallet_keypair: Option<Keypair>,
pub rpc_endpoints: Vec<String>,
pub backup_endpoints: Vec<String>,
}

impl SecureConfig {
pub fn load_secure() -> Result<Self> {
let secret_manager = SecretManager::load()?;
let wallet_keypair = Some(secret_manager.get_wallet_keypair()?);

Ok(Self {
wallet_keypair,
rpc_endpoints: vec![
"https://api.mainnet-beta.solana.com".to_string(),
"https://solana-api.projectserum.com".to_string(),
],
backup_endpoints: vec![
"https://api.devnet.solana.com".to_string(),
],
})
}
}

2. Runtime Security​

// src/security/runtime.rs
use std::collections::HashSet;
use solana_sdk::pubkey::Pubkey;

pub struct SecurityValidator {
allowed_programs: HashSet<Pubkey>,
max_transaction_size: usize,
rate_limiter: RateLimiter,
}

impl SecurityValidator {
pub fn new(allowed_programs: Vec<Pubkey>) -> Self {
Self {
allowed_programs: allowed_programs.into_iter().collect(),
max_transaction_size: 1232, // Solana transaction size limit
rate_limiter: RateLimiter::new(1000, Duration::from_secs(60)),
}
}

pub fn validate_transaction(&self, transaction: &Transaction) -> Result<()> {
// Check transaction size
let serialized_size = bincode::serialized_size(transaction)?;
if serialized_size > self.max_transaction_size as u64 {
return Err(anyhow!("Transaction too large: {} bytes", serialized_size));
}

// Validate all program IDs are allowed
for instruction in &transaction.message.instructions {
let program_id = transaction.message.account_keys[instruction.program_id_index as usize];
if !self.allowed_programs.contains(&program_id) {
return Err(anyhow!("Unauthorized program: {}", program_id));
}
}

// Rate limiting check
self.rate_limiter.check_rate_limit()?;

Ok(())
}
}

struct RateLimiter {
max_requests: u32,
window: Duration,
requests: std::sync::Mutex<Vec<std::time::Instant>>,
}

impl RateLimiter {
fn new(max_requests: u32, window: Duration) -> Self {
Self {
max_requests,
window,
requests: std::sync::Mutex::new(Vec::new()),
}
}

fn check_rate_limit(&self) -> Result<()> {
let now = std::time::Instant::now();
let mut requests = self.requests.lock().unwrap();

// Remove old requests outside window
requests.retain(|&time| now.duration_since(time) <= self.window);

if requests.len() >= self.max_requests as usize {
return Err(anyhow!("Rate limit exceeded"));
}

requests.push(now);
Ok(())
}
}

Production Deployment​

1. Systemd Service Configuration​

# /etc/systemd/system/saros-trading-bot.service
[Unit]
Description=Saros Trading Bot
After=network.target
Wants=network-online.target

[Service]
Type=exec
User=trading-bot
Group=trading-bot
WorkingDirectory=/opt/saros-trading-bot
ExecStart=/opt/saros-trading-bot/bin/trading-bot
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=saros-trading-bot

# Security settings
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/saros-trading-bot/data

# Environment
Environment=RUST_ENV=production
Environment=RUST_LOG=info
EnvironmentFile=/opt/saros-trading-bot/config/.env

# Resource limits
MemoryMax=2G
CPUQuota=200%

[Install]
WantedBy=multi-user.target

2. Logging Configuration​

// src/logging/mod.rs
use tracing_subscriber::{
fmt::layer,
layer::SubscriberExt,
util::SubscriberInitExt,
EnvFilter,
Layer,
};
use tracing_opentelemetry::OpenTelemetryLayer;

pub fn init_logging(config: &MonitoringConfig) -> Result<()> {
let env_filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new(&config.log_level));

let fmt_layer = layer()
.with_target(true)
.with_thread_ids(true)
.with_file(true)
.with_line_number(true);

if config.enable_metrics {
// Production: structured logging with OpenTelemetry
let tracer = opentelemetry_jaeger::new_agent_pipeline()
.with_service_name("saros-trading-bot")
.install_simple()?;

let telemetry_layer = OpenTelemetryLayer::new(tracer);

tracing_subscriber::registry()
.with(env_filter)
.with(fmt_layer)
.with(telemetry_layer)
.init();
} else {
// Development: simple console logging
tracing_subscriber::registry()
.with(env_filter)
.with(fmt_layer)
.init();
}

Ok(())
}

Troubleshooting​

Common Build Issues​

# Clear cargo cache if build issues persist
cargo clean
rm -rf ~/.cargo/registry/cache

# Update Rust toolchain
rustup update stable

# Regenerate Cargo.lock with latest dependencies
rm Cargo.lock
cargo build

# Fix common linking issues on Linux
sudo apt-get install build-essential pkg-config libssl-dev protobuf-compiler

# Fix common issues on macOS
brew install protobuf openssl
export PKG_CONFIG_PATH="/opt/homebrew/lib/pkgconfig"

Performance Debugging​

// Add to Cargo.toml for performance profiling
[dependencies]
pprof = { version = "0.13", features = ["flamegraph", "protobuf-codec"] }

// Example profiling code
#[cfg(feature = "profiling")]
async fn profile_trading_operation() {
let guard = pprof::ProfilerGuard::new(100).unwrap();

// Your trading operation here
execute_trading_strategy().await;

if let Ok(report) = guard.report().build() {
let file = std::fs::File::create("flamegraph.svg").unwrap();
report.flamegraph(file).unwrap();
println!("Flamegraph saved to flamegraph.svg");
}
}

This advanced setup guide provides enterprise-grade configuration for Rust development with Saros SDK, ensuring optimal performance, security, and maintainability for production deployments.