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};
sol! {
#[sol(rpc)]
contract OstiumTradingStorage {
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;
}
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);
}
}
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> {
pub fn new(address: Address, provider: P) -> Self {
let contract = OstiumTradingStorage::new(address, provider);
Self { contract }
}
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,
})
}
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,
})
}
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)
}
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)
}
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)
}
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)
}
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)
}
}