Docs

PerpCity Rust SDK

High-performance Rust SDK for HFT bots and latency-sensitive trading on PerpCity perpetual futures.

The PerpCity Rust SDK is a high-performance Rust library for the PerpCity perpetual futures protocol on Base L2. Built for HFT bots and latency-sensitive trading systems with lock-free nonce management, multi-endpoint transport, and 2-tier state caching.

Why Rust?

  • Zero-cost abstractions -- Async/await with Tokio, no runtime overhead
  • Lock-free nonce management -- AtomicU64 for O(1) nonce acquisition on the hot path
  • Multi-endpoint transport -- Latency-based, round-robin, or hedged RPC routing with circuit breakers
  • 2-tier state caching -- Fast (2s) and slow (60s) TTL layers tuned for Base L2 block times
  • Human-readable API -- f64 prices and margins, SDK handles on-chain 6-decimal conversion

Architecture

LayerDescriptionNetwork Required
Pure MathPrice/tick conversions, position calculations, liquidity mathNo
HFT InfrastructureNonce management, multi-RPC failover, gas caching, latency tracking, tx pipelineNo
Contract InteractionPerpClient, trading functions, USDC approvalYes

Quick Start

use alloy::signers::local::PrivateKeySigner;
use perpcity_sdk::{
    PerpClient, Deployments, OpenTakerParams, Urgency,
    transport::{TransportConfig, Strategy},
};

#[tokio::main]
async fn main() -> perpcity_sdk::Result<()> {
    let signer: PrivateKeySigner = "0xYOUR_PRIVATE_KEY".parse()?;

    let transport = TransportConfig::new(vec![
        "https://base-rpc-url.com".into(),
    ])
    .strategy(Strategy::LatencyBased)
    .build()?;

    let deployments = Deployments {
        perp_manager: "0xPERP_MANAGER".parse()?,
        usdc: "0xUSDC".parse()?,
        ..Default::default()
    };

    let mut client = PerpClient::new_base_mainnet(transport, signer, deployments)?;
    client.sync_nonce().await?;
    client.refresh_gas().await?;
    client.ensure_approval(None).await?;

    let perp_id: B256 = "0xYOUR_PERP_ID".parse()?;

    // Open a 10x long
    let pos_id = client.open_taker(perp_id.into(), OpenTakerParams {
        is_long: true,
        margin: 100.0,
        leverage: 10.0,
        unspecified_amount_limit: 0,
    }, Urgency::Normal).await?;

    // Check live details
    let details = client.get_live_details(pos_id).await?;
    println!("PnL: {:.2}", details.pnl);

    Ok(())
}

Guides

Resources