perpcity_sdk/types.rs
1//! Client-facing types for the PerpCity SDK.
2//!
3//! These types use `f64` for human-readable values (prices, USDC amounts,
4//! leverage) and Alloy's [`Address`] / [`B256`] for on-chain identifiers.
5//! They are the public API surface — users construct these, and the SDK
6//! converts them to wire-format contract types internally.
7//!
8//! Following the [hyperliquid-rust-sdk] pattern: client types are **not**
9//! serializable. Serialization belongs on wire types only.
10
11use alloy::primitives::{Address, B256, U256};
12
13/// Deployed contract addresses for a PerpCity instance.
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct Deployments {
16 /// PerpManager proxy address.
17 pub perp_manager: Address,
18 /// USDC token address.
19 pub usdc: Address,
20 /// Fees module address (if registered).
21 pub fees_module: Option<Address>,
22 /// Margin ratios module address (if registered).
23 pub margin_ratios_module: Option<Address>,
24 /// Lockup period module address (if registered).
25 pub lockup_period_module: Option<Address>,
26 /// Sqrt-price impact limit module address (if registered).
27 pub sqrt_price_impact_limit_module: Option<Address>,
28}
29
30/// Metadata about a perpetual market.
31#[derive(Debug, Clone, PartialEq)]
32pub struct PerpData {
33 /// Unique perp identifier (`PoolId` / `bytes32` on-chain).
34 pub id: B256,
35 /// Tick spacing for the underlying Uniswap V4 pool.
36 pub tick_spacing: i32,
37 /// Current mark price in human-readable units (e.g. `1.05`).
38 pub mark: f64,
39 /// Beacon contract address.
40 pub beacon: Address,
41 /// Leverage and margin constraints.
42 pub bounds: Bounds,
43 /// Fee structure.
44 pub fees: Fees,
45}
46
47/// Leverage and margin constraints for a perpetual market.
48///
49/// All values are human-readable: leverage as a multiplier (e.g. `10.0`),
50/// margin in USDC (e.g. `5.0`), and ratios as fractions (e.g. `0.005`).
51#[derive(Debug, Clone, Copy, PartialEq)]
52pub struct Bounds {
53 /// Minimum margin to open a position, in USDC (e.g. `5.0`).
54 pub min_margin: f64,
55 /// Minimum taker leverage (e.g. `1.0`).
56 pub min_taker_leverage: f64,
57 /// Maximum taker leverage (e.g. `100.0`).
58 pub max_taker_leverage: f64,
59 /// Margin ratio at which taker liquidation occurs, as a fraction
60 /// (e.g. `0.005` = 0.5%).
61 pub liquidation_taker_ratio: f64,
62}
63
64/// Fee percentages for a perpetual market, expressed as fractions of 1.
65///
66/// For example, `0.001` means 0.1% (which is `1_000` on-chain at 1e6 scale).
67#[derive(Debug, Clone, Copy, PartialEq)]
68pub struct Fees {
69 /// Fee paid to the perp creator.
70 pub creator_fee: f64,
71 /// Fee that goes to the insurance fund.
72 pub insurance_fee: f64,
73 /// Fee earned by liquidity providers.
74 pub lp_fee: f64,
75 /// Fee charged on liquidations.
76 pub liquidation_fee: f64,
77}
78
79/// Real-time position metrics, typically from a `quoteClosePosition` call.
80///
81/// All USDC values are human-readable (e.g. `12.50` not `12_500_000`).
82#[derive(Debug, Clone, Copy, PartialEq)]
83pub struct LiveDetails {
84 /// Unrealized PnL in USDC.
85 pub pnl: f64,
86 /// Accumulated funding payment in USDC (positive = received).
87 pub funding_payment: f64,
88 /// Current effective margin in USDC.
89 pub effective_margin: f64,
90 /// Whether this position would be liquidated at the current price.
91 pub is_liquidatable: bool,
92}
93
94/// Taker open interest for a perp market, in USDC.
95#[derive(Debug, Clone, Copy, PartialEq)]
96pub struct OpenInterest {
97 /// Total long open interest in USDC.
98 pub long_oi: f64,
99 /// Total short open interest in USDC.
100 pub short_oi: f64,
101}
102
103/// Client-facing parameters for opening a taker (long/short) position.
104///
105/// The SDK converts these to contract types automatically:
106/// - `margin` → scaled to 6 decimals
107/// - `leverage` → converted to margin ratio via `1e6 / leverage`
108#[derive(Debug, Clone, Copy, PartialEq)]
109pub struct OpenTakerParams {
110 /// `true` for long, `false` for short.
111 pub is_long: bool,
112 /// Margin in USDC (e.g. `100.0` for 100 USDC).
113 pub margin: f64,
114 /// Leverage multiplier (e.g. `10.0` for 10×).
115 pub leverage: f64,
116 /// Slippage protection: max unspecified token amount. `0` = no limit.
117 pub unspecified_amount_limit: u128,
118}
119
120/// Client-facing parameters for opening a maker (LP) position.
121///
122/// The SDK converts these to contract types automatically:
123/// - `margin` → scaled to 6 decimals
124/// - `price_lower` / `price_upper` → converted to ticks
125#[derive(Debug, Clone, Copy, PartialEq)]
126pub struct OpenMakerParams {
127 /// Margin in USDC (e.g. `1000.0`).
128 pub margin: f64,
129 /// Lower bound of the price range.
130 pub price_lower: f64,
131 /// Upper bound of the price range.
132 pub price_upper: f64,
133 /// Liquidity amount to provide.
134 pub liquidity: u128,
135 /// Maximum amount of token0 willing to deposit.
136 pub max_amt0_in: u128,
137 /// Maximum amount of token1 willing to deposit.
138 pub max_amt1_in: u128,
139}
140
141/// Client-facing parameters for closing a position.
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub struct CloseParams {
144 /// Minimum amount of token0 to receive (slippage protection).
145 pub min_amt0_out: u128,
146 /// Minimum amount of token1 to receive (slippage protection).
147 pub min_amt1_out: u128,
148 /// Maximum amount of token1 willing to pay.
149 pub max_amt1_in: u128,
150}
151
152/// Result of closing a position.
153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub struct CloseResult {
155 /// Transaction hash.
156 pub tx_hash: B256,
157 /// If the close was partial, the remaining position's NFT token ID.
158 /// `None` means the position was fully closed.
159 pub remaining_position_id: Option<U256>,
160}