pub struct PerpClient { /* private fields */ }Expand description
High-level client for the PerpCity protocol.
Combines transport, signing, transaction pipeline, state caching, and
contract bindings into one ergonomic API. All write operations go
through the TxPipeline for zero-RPC-on-hot-path nonce/gas resolution.
Read operations use the StateCache to avoid redundant RPC calls.
Implementations§
Source§impl PerpClient
impl PerpClient
Sourcepub fn new(
transport: HftTransport,
signer: PrivateKeySigner,
deployments: Deployments,
chain_id: u64,
) -> Result<Self>
pub fn new( transport: HftTransport, signer: PrivateKeySigner, deployments: Deployments, chain_id: u64, ) -> Result<Self>
Create a new PerpClient.
transport: Multi-endpoint RPC transport (fromcrate::TransportConfig)signer: Private key for signing transactionsdeployments: Contract addresses for this PerpCity instancechain_id: Chain ID (8453 for Base mainnet, 84532 for Base Sepolia)
This does NOT make any network calls. Call Self::refresh_gas and
Self::sync_nonce before submitting transactions.
Sourcepub fn new_base_mainnet(
transport: HftTransport,
signer: PrivateKeySigner,
deployments: Deployments,
) -> Result<Self>
pub fn new_base_mainnet( transport: HftTransport, signer: PrivateKeySigner, deployments: Deployments, ) -> Result<Self>
Create a client pre-configured for Base mainnet.
Sourcepub async fn sync_nonce(&self) -> Result<()>
pub async fn sync_nonce(&self) -> Result<()>
Sync the nonce manager with the on-chain transaction count.
Must be called before the first transaction. After this, the pipeline manages nonces locally (zero RPC per transaction).
Sourcepub async fn refresh_gas(&self) -> Result<()>
pub async fn refresh_gas(&self) -> Result<()>
Refresh the gas cache from the latest block header.
Fetches the latest block directly in a single RPC call and extracts
the base fee for EIP-1559 fee computation. Should be called
periodically (every 1-2 seconds on Base L2) or from a newHeads
subscription callback.
Sourcepub fn set_base_fee(&self, base_fee: u64)
pub fn set_base_fee(&self, base_fee: u64)
Inject a base fee from an external source (e.g. a shared poller).
Updates the gas cache as if refresh_gas had been called, but without
any RPC calls. The cache TTL is reset to now.
Sourcepub fn base_fee(&self) -> Option<u64>
pub fn base_fee(&self) -> Option<u64>
Return the current cached base fee, if any (ignores TTL).
Intended for reading the base fee after refresh_gas in order to
distribute it to other clients via set_base_fee.
Sourcepub fn set_gas_ttl(&self, ttl_ms: u64)
pub fn set_gas_ttl(&self, ttl_ms: u64)
Override the gas cache TTL (milliseconds).
When gas is managed externally via set_base_fee,
the default 2s TTL may be too tight. Set this to match the poller’s
cadence with headroom (e.g. tick_secs * 2 * 1000).
Sourcepub async fn open_taker(
&self,
perp_id: B256,
params: &OpenTakerParams,
urgency: Urgency,
) -> Result<OpenResult>
pub async fn open_taker( &self, perp_id: B256, params: &OpenTakerParams, urgency: Urgency, ) -> Result<OpenResult>
Open a taker (long/short) position.
Returns an OpenResult with the position ID and entry deltas
parsed from the PositionOpened event, so callers can construct
position tracking data without a follow-up RPC read.
§Errors
Returns PerpCityError::TxReverted if the transaction reverts,
or PerpCityError::EventNotFound if the PositionOpened event
is missing from the receipt.
Sourcepub async fn open_maker(
&self,
perp_id: B256,
params: &OpenMakerParams,
urgency: Urgency,
) -> Result<OpenResult>
pub async fn open_maker( &self, perp_id: B256, params: &OpenMakerParams, urgency: Urgency, ) -> Result<OpenResult>
Open a maker (LP) position within a price range.
Converts price_lower/price_upper to aligned ticks internally.
Returns an OpenResult with the position ID and entry deltas.
Sourcepub async fn close_position(
&self,
pos_id: U256,
params: &CloseParams,
urgency: Urgency,
) -> Result<CloseResult>
pub async fn close_position( &self, pos_id: U256, params: &CloseParams, urgency: Urgency, ) -> Result<CloseResult>
Close a position (taker or maker).
Returns a CloseResult with the transaction hash and optional
remaining position ID (for partial closes).
Sourcepub async fn adjust_notional(
&self,
pos_id: U256,
params: &AdjustNotionalParams,
urgency: Urgency,
) -> Result<AdjustNotionalResult>
pub async fn adjust_notional( &self, pos_id: U256, params: &AdjustNotionalParams, urgency: Urgency, ) -> Result<AdjustNotionalResult>
Adjust the notional exposure of a taker position.
usd_delta > 0: receive USD by selling perp tokens (reduce exposure)usd_delta < 0: spend USD to buy perp tokens (increase exposure)
Sourcepub async fn adjust_margin(
&self,
pos_id: U256,
params: &AdjustMarginParams,
urgency: Urgency,
) -> Result<AdjustMarginResult>
pub async fn adjust_margin( &self, pos_id: U256, params: &AdjustMarginParams, urgency: Urgency, ) -> Result<AdjustMarginResult>
Add or remove margin from a position.
margin_delta > 0: deposit more marginmargin_delta < 0: withdraw margin
Sourcepub async fn ensure_approval(&self, min_amount: U256) -> Result<Option<B256>>
pub async fn ensure_approval(&self, min_amount: U256) -> Result<Option<B256>>
Ensure USDC is approved for the PerpManager to spend.
Checks current allowance and only sends an approve transaction
if the allowance is below min_amount. Approves for U256::MAX
(infinite approval) to avoid repeated approve calls.
Sourcepub async fn get_perp_config(&self, perp_id: B256) -> Result<PerpData>
pub async fn get_perp_config(&self, perp_id: B256) -> Result<PerpData>
Get the full perp configuration, fees, and bounds for a market.
Uses the StateCache for fees and bounds (60s TTL). The perp
config itself is always fetched fresh (it’s cheap and rarely changes).
Sourcepub async fn get_perp_data(&self, perp_id: B256) -> Result<(Address, i32, f64)>
pub async fn get_perp_data(&self, perp_id: B256) -> Result<(Address, i32, f64)>
Get perp data: beacon, tick spacing, and current mark price.
Lighter-weight than Self::get_perp_config — skips fees/bounds lookups.
Sourcepub async fn get_position(&self, pos_id: U256) -> Result<Position>
pub async fn get_position(&self, pos_id: U256) -> Result<Position>
Get an on-chain position by its NFT token ID.
Returns the raw contract position struct. Use crate::math::position
functions to compute derived values (entry price, PnL, etc.).
Sourcepub async fn get_positions_by_owner(&self, owner: Address) -> Result<Vec<U256>>
pub async fn get_positions_by_owner(&self, owner: Address) -> Result<Vec<U256>>
Get all position IDs owned by an address.
Iterates through all minted position NFTs (1..nextPosId) and returns
those owned by owner. Burned or non-existent tokens are skipped.
Note: This is O(n) in total positions ever minted. For high-throughput use cases, prefer the bot API’s position endpoints instead.
Sourcepub async fn get_mark_price(&self, perp_id: B256) -> Result<f64>
pub async fn get_mark_price(&self, perp_id: B256) -> Result<f64>
Get the current mark price for a perp (TWAP with 1-second lookback).
Uses the fast cache layer (2s TTL).
Sourcepub async fn get_index_price(&self, beacon: Address) -> Result<f64>
pub async fn get_index_price(&self, beacon: Address) -> Result<f64>
Get the oracle index price from a beacon contract.
The beacon address is available from PerpData.beacon (returned by
get_perp_config).
Sourcepub async fn get_live_details(&self, pos_id: U256) -> Result<LiveDetails>
pub async fn get_live_details(&self, pos_id: U256) -> Result<LiveDetails>
Simulate closing a position to get live PnL, funding, and liquidation status.
This is a read-only call (no transaction sent).
Sourcepub async fn get_open_interest(&self, perp_id: B256) -> Result<OpenInterest>
pub async fn get_open_interest(&self, perp_id: B256) -> Result<OpenInterest>
Get taker open interest for a perp market.
Sourcepub async fn quote_open_taker(
&self,
perp_id: B256,
params: &OpenTakerParams,
) -> Result<OpenTakerQuote>
pub async fn quote_open_taker( &self, perp_id: B256, params: &OpenTakerParams, ) -> Result<OpenTakerQuote>
Simulate opening a taker position without sending a transaction.
Returns the perp and USD deltas that would result from the trade. Useful for estimating price impact before committing capital.
Sourcepub async fn quote_open_maker(
&self,
perp_id: B256,
params: &OpenMakerParams,
) -> Result<OpenMakerQuote>
pub async fn quote_open_maker( &self, perp_id: B256, params: &OpenMakerParams, ) -> Result<OpenMakerQuote>
Simulate opening a maker (LP) position without sending a transaction.
Returns the perp and USD deltas that would result from the position.
Sourcepub async fn quote_swap(
&self,
perp_id: B256,
zero_for_one: bool,
is_exact_in: bool,
amount: U256,
sqrt_price_limit_x96: U256,
) -> Result<SwapQuote>
pub async fn quote_swap( &self, perp_id: B256, zero_for_one: bool, is_exact_in: bool, amount: U256, sqrt_price_limit_x96: U256, ) -> Result<SwapQuote>
Simulate a raw swap in a perp’s Uniswap V4 pool without executing.
This is the lowest-level quote — it simulates a single pool swap and returns the resulting token deltas. Use this to estimate price impact for a given trade size.
§Arguments
perp_id— The perp market to quote against.zero_for_one— Swap direction:truesells token0 for token1.is_exact_in—trueifamountis the exact input;falsefor exact output.amount— The swap amount (scaled to 6 decimals).sqrt_price_limit_x96— Price limit in sqrtPriceX96 format. Use0for no limit.
Sourcepub async fn get_funding_rate(&self, perp_id: B256) -> Result<f64>
pub async fn get_funding_rate(&self, perp_id: B256) -> Result<f64>
Get the funding rate per second for a perp, converted to a daily rate.
Uses the fast cache layer (2s TTL).
Sourcepub async fn get_usdc_balance(&self) -> Result<f64>
pub async fn get_usdc_balance(&self) -> Result<f64>
Get the USDC balance of the signer’s address.
Uses the fast cache layer (2s TTL).
Sourcepub async fn get_balances(&self, address: Address) -> Result<(f64, U256)>
pub async fn get_balances(&self, address: Address) -> Result<(f64, U256)>
Get the USDC and ETH balances of an address in a single RPC call.
Uses Multicall3 to bundle a balanceOf (USDC) and getEthBalance
(native ETH) into one eth_call. The RPC provider charges 1 CU
regardless of how many sub-calls the multicall executes.
Returns (usdc_balance, eth_balance) where USDC is in human units
(e.g. 100.0 = 100 USDC) and ETH is in wei.
Sourcepub async fn get_balances_batch(
&self,
addresses: &[Address],
) -> Result<Vec<(f64, U256)>>
pub async fn get_balances_batch( &self, addresses: &[Address], ) -> Result<Vec<(f64, U256)>>
Get the USDC and ETH balances for multiple addresses in a single RPC call.
Uses Multicall3 to bundle N × balanceOf + N × getEthBalance into
one eth_call. For 10 addresses, this is 1 CU instead of 20.
Returns a Vec<(usdc_balance, eth_balance)> in the same order as
the input addresses.
Sourcepub async fn get_perp_snapshot(
&self,
perp_id: B256,
) -> Result<(PerpData, PerpSnapshot)>
pub async fn get_perp_snapshot( &self, perp_id: B256, ) -> Result<(PerpData, PerpSnapshot)>
Get perp config and live market data in two multicalls (2 CUs total).
Phase 1 multicalls cfgs + timeWeightedAvgSqrtPriceX96 +
fundingPerSecondX96 + takerOpenInterest against PerpManager
(4 reads → 1 CU). Phase 2 calls index() on the beacon returned
by phase 1 (1 CU).
Returns (PerpData, PerpSnapshot) — static config and live market
data. Replaces the typical startup sequence of 5+ individual RPCs.
Sourcepub fn deployments(&self) -> &Deployments
pub fn deployments(&self) -> &Deployments
The deployed contract addresses.
Sourcepub fn provider(&self) -> &RootProvider<Ethereum>
pub fn provider(&self) -> &RootProvider<Ethereum>
The underlying Alloy provider (for advanced queries).
Sourcepub fn wallet(&self) -> &EthereumWallet
pub fn wallet(&self) -> &EthereumWallet
The signing wallet (for building signed transactions outside the SDK).
Sourcepub fn transport(&self) -> &HftTransport
pub fn transport(&self) -> &HftTransport
The underlying HFT transport (for health diagnostics).
Sourcepub fn invalidate_fast_cache(&self)
pub fn invalidate_fast_cache(&self)
Invalidate the fast cache layer (prices, funding, balance).
Call on new-block events to ensure fresh data.
Sourcepub fn invalidate_all_cache(&self)
pub fn invalidate_all_cache(&self)
Invalidate all cached state.
Sourcepub fn confirm_tx(&self, tx_hash: &[u8; 32])
pub fn confirm_tx(&self, tx_hash: &[u8; 32])
Confirm a transaction as mined. Removes from in-flight tracking.
Sourcepub fn fail_tx(&self, tx_hash: &[u8; 32])
pub fn fail_tx(&self, tx_hash: &[u8; 32])
Mark a transaction as failed. Releases the nonce if possible.
Sourcepub fn in_flight_count(&self) -> usize
pub fn in_flight_count(&self) -> usize
Number of currently in-flight (unconfirmed) transactions.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for PerpClient
impl !RefUnwindSafe for PerpClient
impl Send for PerpClient
impl Sync for PerpClient
impl Unpin for PerpClient
impl UnsafeUnpin for PerpClient
impl !UnwindSafe for PerpClient
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more