ostium-rust-sdk 0.1.0

Rust SDK for interacting with the Ostium trading platform on Arbitrum
Documentation
use alloy::network::Network;
use alloy::primitives::{Address, U256};
use alloy::providers::Provider;
use alloy::sol_types::sol;

use crate::error::{OstiumError, Result};
use crate::types::{OpenLimitOrder, Trade};

// Define the Trading Storage contract interface
sol! {
    #[sol(rpc)]
    contract OstiumTradingStorage {
        // Structs
        struct Trade {
            uint256 collateral;
            uint192 openPrice;
            uint192 tp;
            uint192 sl;
            address trader;
            uint32 leverage;
            uint16 pairIndex;
            uint8 index;
            bool buy;
        }

        struct OpenLimitOrder {
            uint256 collateral;
            uint192 targetPrice;
            uint192 tp;
            uint192 sl;
            address trader;
            uint32 leverage;
            uint32 createdAt;
            uint32 lastUpdated;
            uint16 pairIndex;
            uint8 orderType;
            uint8 index;
            bool buy;
        }

        // View functions
        function getTrade(address trader, uint16 pairIndex, uint8 index) external view returns (Trade memory);
        function getOpenLimitOrder(address trader, uint16 pairIndex, uint8 index) external view returns (OpenLimitOrder memory);
        function getOpenLimitOrdersCount(address trader, uint16 pairIndex) external view returns (uint8);
        function getTradesCount(address trader, uint16 pairIndex) external view returns (uint8);
        function openInterestUsdc(uint16 pairIndex, bool long) external view returns (uint256);
        function getPairIndex(string calldata from, string calldata to) external view returns (uint16);
        function getTradingContract() external view returns (address);
        function getCallbacksContract() external view returns (address);
    }
}

/// Trading Storage contract wrapper
pub struct TradingStorageContract<P: Provider<N>, N: Network = alloy::network::Ethereum> {
    contract: OstiumTradingStorage::OstiumTradingStorageInstance<P, N>,
}

impl<P: Provider<N>, N: Network> TradingStorageContract<P, N> {
    /// Create a new Trading Storage contract instance
    pub fn new(address: Address, provider: P) -> Self {
        let contract = OstiumTradingStorage::new(address, provider);
        Self { contract }
    }

    /// Get a trade by trader, pair index, and index
    pub async fn get_trade(&self, trader: Address, pair_index: u16, index: u8) -> Result<Trade> {
        let trade = self
            .contract
            .getTrade(trader, pair_index, index)
            .call()
            .await
            .map_err(|e| OstiumError::contract(format!("Failed to get trade: {}", e)))?;

        Ok(Trade {
            collateral: trade.collateral,
            open_price: trade.openPrice.try_into().map_err(|e| {
                OstiumError::conversion(format!("Failed to convert openPrice: {}", e))
            })?,
            tp: trade
                .tp
                .try_into()
                .map_err(|e| OstiumError::conversion(format!("Failed to convert tp: {}", e)))?,
            sl: trade
                .sl
                .try_into()
                .map_err(|e| OstiumError::conversion(format!("Failed to convert sl: {}", e)))?,
            trader: trade.trader,
            leverage: trade.leverage,
            pair_index: trade.pairIndex,
            index: trade.index,
            buy: trade.buy,
        })
    }

    /// Get an open limit order
    pub async fn get_open_limit_order(
        &self,
        trader: Address,
        pair_index: u16,
        index: u8,
    ) -> Result<OpenLimitOrder> {
        let order = self
            .contract
            .getOpenLimitOrder(trader, pair_index, index)
            .call()
            .await
            .map_err(|e| OstiumError::contract(format!("Failed to get open limit order: {}", e)))?;

        Ok(OpenLimitOrder {
            collateral: order.collateral,
            target_price: order.targetPrice.try_into().map_err(|e| {
                OstiumError::conversion(format!("Failed to convert targetPrice: {}", e))
            })?,
            tp: order
                .tp
                .try_into()
                .map_err(|e| OstiumError::conversion(format!("Failed to convert tp: {}", e)))?,
            sl: order
                .sl
                .try_into()
                .map_err(|e| OstiumError::conversion(format!("Failed to convert sl: {}", e)))?,
            trader: order.trader,
            leverage: order.leverage,
            created_at: order.createdAt,
            last_updated: order.lastUpdated,
            pair_index: order.pairIndex,
            order_type: order.orderType,
            index: order.index,
            buy: order.buy,
        })
    }

    /// Get the count of open limit orders for a trader and pair
    pub async fn get_open_limit_orders_count(
        &self,
        trader: Address,
        pair_index: u16,
    ) -> Result<u8> {
        let count = self
            .contract
            .getOpenLimitOrdersCount(trader, pair_index)
            .call()
            .await
            .map_err(|e| {
                OstiumError::contract(format!("Failed to get open limit orders count: {}", e))
            })?;

        Ok(count)
    }

    /// Get the count of trades for a trader and pair
    pub async fn get_trades_count(&self, trader: Address, pair_index: u16) -> Result<u8> {
        let count = self
            .contract
            .getTradesCount(trader, pair_index)
            .call()
            .await
            .map_err(|e| OstiumError::contract(format!("Failed to get trades count: {}", e)))?;

        Ok(count)
    }

    /// Get the open interest in USDC for a pair
    pub async fn open_interest_usdc(&self, pair_index: u16, long: bool) -> Result<U256> {
        let oi = self
            .contract
            .openInterestUsdc(pair_index, long)
            .call()
            .await
            .map_err(|e| OstiumError::contract(format!("Failed to get open interest: {}", e)))?;

        Ok(oi)
    }

    /// Get the pair index for a trading pair
    pub async fn get_pair_index(&self, from: &str, to: &str) -> Result<u16> {
        let index = self
            .contract
            .getPairIndex(from.to_string(), to.to_string())
            .call()
            .await
            .map_err(|e| OstiumError::contract(format!("Failed to get pair index: {}", e)))?;

        Ok(index)
    }

    /// Get the trading contract address
    pub async fn get_trading_contract(&self) -> Result<Address> {
        let address = self
            .contract
            .getTradingContract()
            .call()
            .await
            .map_err(|e| OstiumError::contract(format!("Failed to get trading contract: {}", e)))?;

        Ok(address)
    }
}