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 Arbitrum. Built for HFT bots and latency-sensitive trading systems with lock-free nonce management, read/write endpoint splitting, Multicall3 batching, cached gas estimation, and block-pinned maker-equity previews.
Why Rust?
- Zero-cost abstractions -- Async/await with Tokio, no runtime overhead
- Lock-free nonce management --
AtomicU64for O(1) nonce acquisition on the hot path - Read/write endpoint splitting -- Route reads to free public RPCs, writes to paid endpoints, with automatic circuit-breaker failover
- Multicall3 batching -- Fetch N balances or a full market snapshot in a single RPC call (1 CU instead of N)
- Universal pre-flight simulation -- Every send is simulated before broadcast; would-be reverts decode into typed errors instead of burning gas on-chain
- Local swap simulation -- Quote taker trades against a block-pinned order book with contract-exact integer math, no RPC on the quote path
- Maker equity previews -- Batched, block-pinned settle previews for open maker positions, validated against a real on-chain liquidation
- Human-readable API -- f64 prices and margins, SDK handles on-chain 6-decimal conversion
Architecture
| Layer | Description | Network Required |
|---|---|---|
| Pure Math | Price/tick conversions, position calculations, liquidity math, swap simulation, maker settle math | No |
| HFT Infrastructure | Nonce management, multi-RPC failover, fee/gas caching, latency tracking, tx pipeline | No |
| Contract Interaction | PerpClient (one per market), trading functions, liquidations, Multicall3 batching | Yes |
Each market is its own Perp contract, identified by its address -- a PerpClient is constructed per market and its methods need no market parameter.
Quick Start
use alloy::primitives::U256;
use alloy::signers::local::PrivateKeySigner;
use perpcity_sdk::prelude::*;
#[tokio::main]
async fn main() -> perpcity_sdk::Result<()> {
let signer: PrivateKeySigner = "0xYOUR_PRIVATE_KEY".parse()?;
let transport = HftTransport::new(
TransportConfig::builder()
.shared_endpoint("https://arb-mainnet.g.alchemy.com/v2/KEY")
.read_endpoint("https://arbitrum-one-rpc.publicnode.com")
.build()?,
)?;
let deployments = Deployments {
perp: "0xYOUR_PERP".parse()?,
usdc: ARBITRUM_USDC,
pool_manager: ARBITRUM_POOL_MANAGER,
};
let client = PerpClient::new_arbitrum(transport, signer, deployments)?;
client.sync_nonce().await?;
client.refresh_gas().await?;
client.ensure_approval(U256::MAX).await?;
// Fetch config + live market data in 2 multicalls
let (config, snapshot) = client.get_perp_snapshot().await?;
println!("Mark: {:.2}, Index: {:.2}", snapshot.mark_price, snapshot.index_price);
// Open a long: 100 USDC margin, +1 perp of exposure
let result = client.open_taker(&OpenTakerParams {
margin: 100.0,
perp_delta: 1.0, // positive = long, negative = short
amt1_limit: 0, // slippage limit, 0 = no limit
}, Urgency::Normal).await?;
println!("Position opened: {}", result.pos_id);
// Close it (pass the position's current perp delta)
let closed = client
.close_taker(result.pos_id, result.perp_delta, Urgency::Normal)
.await?;
println!("Closed: perp {:+.6}, usd {:+.2}", closed.perp_delta, closed.usd_delta);
Ok(())
}Guides
Resources
- GitHub: perpcity-rust-sdk repository
- Crate: perpcity-sdk on crates.io
- TypeScript SDK: For a higher-level alternative, see the PerpCity TypeScript SDK
- Python SDK: For Python, see the PerpCity Python SDK
- Zig SDK: For Zig, see the PerpCity Zig SDK