API Reference
Complete reference for the PerpCity Zig SDK -- context, trading, math, and HFT infrastructure.
Complete reference for the PerpCity Zig SDK.
PerpCityContext
The main client for interacting with the PerpCity protocol.
const sdk = @import("perpcity_sdk");
var ctx = sdk.context.PerpCityContext.init(
allocator,
"https://base-rpc-url.com",
private_key,
.{
.perp_manager = perp_manager_addr,
.usdc = usdc_addr,
},
);
ctx.fixPointers();
defer ctx.deinit();Methods
| Method | Returns | Description |
|---|---|---|
init(allocator, rpc_url, private_key, deployments) | PerpCityContext | Create context (call fixPointers() after) |
fixPointers() | void | Fix internal pointer references |
setupForTrading() | !void | Approve max USDC spending |
getPerpConfig(perp_id) | !PerpConfig | Fetch and cache perp configuration |
getPerpData(perp_id) | !PerpData | Fetch market data (mark price, bounds, fees) |
getUserData(address, positions) | !UserData | Fetch user balance and position details |
getOpenPositionData(perp_id, pos_id, is_long, is_maker) | !OpenPositionData | Fetch live position details |
getPositionRawData(pos_id) | !PositionRawData | Fetch raw on-chain position data |
deinit() | void | Free all resources |
Trading Functions
openTakerPosition
const position = try sdk.perp_manager.openTakerPosition(&ctx, perp_id, .{
.is_long = true,
.margin = 1000.0,
.leverage = 10.0,
.unspecified_amount_limit = 0,
});Opens a leveraged long or short position. Returns OpenPosition.
openMakerPosition
const position = try sdk.perp_manager.openMakerPosition(&ctx, perp_id, .{
.margin = 10000.0,
.price_lower = 2900.0,
.price_upper = 3100.0,
.liquidity = 1000000,
.max_amt0_in = 1000000,
.max_amt1_in = 1000000,
});Opens a liquidity provider position. Aligns price range to tick spacing automatically.
closePosition
const result = try sdk.perp_manager.closePosition(&ctx, perp_id, position_id, .{
.min_amt0_out = 0,
.min_amt1_out = 0,
.max_amt1_in = 1000000,
});adjustNotional / adjustMargin
_ = try sdk.perp_manager.adjustNotional(&ctx, .{
.position_id = pos_id,
.usd_delta = 5000,
.perp_limit = 0,
});
_ = try sdk.perp_manager.adjustMargin(&ctx, .{
.position_id = pos_id,
.margin_delta = 1000,
});createPerp
const perp_id = try sdk.perp_manager.createPerp(&ctx, .{
.starting_price = 3000.0,
.beacon = beacon_addr,
});OpenPosition
Returned by openTakerPosition and openMakerPosition.
const live = try position.liveDetails();
const result = try position.closePosition(.{ ... });
_ = try position.adjustNotional(5000, 0);
_ = try position.adjustMargin(1000);
const hex = position.perpIdHex(); // [64]u8 hex stringCalculation Functions
Pure math -- no network required. Available via both perpcity_sdk and standalone math_root module.
Position Math
| Function | Returns | Description |
|---|---|---|
calculateEntryPrice(raw_data) | f64 | Entry price from raw deltas |
calculatePositionSize(raw_data) | f64 | Position size in base asset |
calculatePositionValue(raw_data, mark_price) | f64 | Notional value at mark price |
calculateLeverage(position_value, effective_margin) | f64 | Current leverage ratio |
calculateLiquidationPrice(raw_data, is_long) | ?f64 | Liquidation price |
Conversions
| Function | Returns | Description |
|---|---|---|
priceToSqrtPriceX96(price) | !u256 | Price to Uniswap V4 sqrtPriceX96 |
sqrtPriceX96ToPrice(sqrt) | !f64 | sqrtPriceX96 to decimal price |
priceToTick(price, round_down) | !i32 | Price to Uniswap tick |
tickToPrice(tick) | f64 | Tick to price (1.0001^tick) |
scale6Decimals(amount) | !i128 | Scale to 6-decimal USDC format |
scaleFrom6Decimals(value) | f64 | Scale from 6-decimal format |
Liquidity
| Function | Returns | Description |
|---|---|---|
getSqrtRatioAtTick(tick) | !u256 | sqrtPriceX96 for a tick |
estimateLiquidity(tick_lower, tick_upper, usd_scaled) | !u256 | Liquidity for USD amount |
calculateLiquidityForTargetRatio(margin_scaled, tick_lower, tick_upper, target_ratio) | !u256 | Liquidity for target margin ratio |
HFT Infrastructure
Nonce Manager
Lock-free atomic nonce acquisition for high-throughput trading.
var nonce_mgr = sdk.nonce.HftNonceManager.init(allocator, starting_nonce);
const nonce = nonce_mgr.acquireNonce(); // lock-free atomic
try nonce_mgr.trackSubmission(nonce, tx_hash);
nonce_mgr.confirmNonce(nonce); // on success
nonce_mgr.releaseNonce(nonce); // on failure
nonce_mgr.resync(on_chain_nonce);Gas Cache
Pre-computed gas limits and EIP-1559 fee caching with urgency levels.
| Operation | Gas Limit |
|---|---|
APPROVE | 60,000 |
OPEN_TAKER_POS | 500,000 |
OPEN_MAKER_POS | 600,000 |
CLOSE_POSITION | 400,000 |
ADJUST_NOTIONAL | 350,000 |
ADJUST_MARGIN | 250,000 |
Urgency Levels: low, normal, high, critical -- each with escalating max fee multipliers.
var cache = sdk.gas.GasCache.init(.{});
cache.updateFromBlock(base_fee, now_ms);
const fees = cache.feesForUrgency(.critical, now_ms);Multi-RPC Provider
Automatic failover across multiple RPC endpoints with health tracking.
var rpc = try sdk.multi_rpc.MultiRpcProvider.init(allocator, &.{
"https://primary-rpc.com",
"https://fallback-rpc.com",
});
const endpoint = rpc.selectEndpoint(now_ms);Latency Tracker
Rolling window (1024 samples) with p50/p95/p99 percentiles.
var tracker = sdk.latency.LatencyTracker{};
tracker.recordSample(latency_ns);
const stats = tracker.getStats(); // .p50_ns, .p95_ns, .p99_nsState Cache
Multi-layer TTL caching tuned for Base L2 block times.
var cache = sdk.state_cache.StateCache.init(allocator, .{
.slow_ttl = 60, // Fees, bounds (60s)
.fast_ttl = 2, // Mark prices (2s, ~1 Base L2 block)
});Position Manager
Position tracking with stop-loss, take-profit, and trailing stop triggers.
var pm = sdk.position_manager.PositionManager.init(allocator);
try pm.track(.{
.perp_id = perp_id,
.position_id = pos_id,
.is_long = true,
.is_maker = false,
.entry_price = 3000.0,
.margin = 1000.0,
.stop_loss = 2800.0,
.take_profit = 3500.0,
.trailing_stop_pct = 0.05,
});
const actions = pm.checkTriggers(current_price);Types
Core
pub const Address = [20]u8;
pub const Bytes32 = [32]u8;
pub const PerpCityDeployments = struct {
perp_manager: Address,
usdc: Address,
fees_module: ?Address = null,
margin_ratios_module: ?Address = null,
lockup_period_module: ?Address = null,
sqrt_price_impact_limit_module: ?Address = null,
};Market Data
pub const PerpData = struct {
id: Bytes32, tick_spacing: i24, mark: f64,
beacon: Address, bounds: Bounds, fees: Fees,
};
pub const Bounds = struct {
min_margin: f64, min_taker_leverage: f64,
max_taker_leverage: f64, liquidation_taker_ratio: f64,
};
pub const Fees = struct {
creator_fee: f64, insurance_fee: f64,
lp_fee: f64, liquidation_fee: f64,
};Position
pub const OpenPositionData = struct {
perp_id: Bytes32, position_id: u256,
is_long: ?bool = null, is_maker: ?bool = null,
live_details: LiveDetails,
};
pub const LiveDetails = struct {
pnl: f64, funding_payment: f64,
effective_margin: f64, is_liquidatable: bool,
};
pub const PositionRawData = struct {
perp_id: Bytes32, position_id: u256, margin: f64,
entry_perp_delta: i256, entry_usd_delta: i256,
margin_ratios: MarginRatios,
};Parameters
pub const OpenTakerPositionParams = struct {
is_long: bool, margin: f64, leverage: f64,
unspecified_amount_limit: u128,
};
pub const OpenMakerPositionParams = struct {
margin: f64, price_lower: f64, price_upper: f64,
liquidity: u128, max_amt0_in: u128, max_amt1_in: u128,
};
pub const ClosePositionParams = struct {
min_amt0_out: u128, min_amt1_out: u128, max_amt1_in: u128,
};
pub const AdjustNotionalParams = struct {
position_id: u256, usd_delta: i128, perp_limit: u128,
};
pub const AdjustMarginParams = struct {
position_id: u256, margin_delta: i128,
};Error Handling
const position = sdk.perp_manager.openTakerPosition(&ctx, perp_id, params) catch |err| {
switch (err) {
error.MarginMustBePositive => ...,
error.TransactionReverted => ...,
error.RpcError => ...,
else => ...,
}
};| Error | Description |
|---|---|
MarginMustBePositive | Margin must be > 0 |
LeverageMustBePositive | Leverage must be > 0 |
InvalidPriceRange | Lower price >= upper price |
TransactionReverted | On-chain transaction reverted |
RpcError | Network or RPC error |
InsufficientFunds | Wallet has insufficient funds |
ModuleAddressRequired | Required module address not set |