use crate::core::types::AccountType;
#[derive(Debug, Clone)]
pub struct DydxUrls {
pub indexer_rest: &'static str,
pub indexer_ws: &'static str,
}
impl DydxUrls {
pub const MAINNET: Self = Self {
indexer_rest: "https://indexer.dydx.trade/v4",
indexer_ws: "wss://indexer.dydx.trade/v4/ws",
};
pub const TESTNET: Self = Self {
indexer_rest: "https://indexer.v4testnet.dydx.exchange/v4",
indexer_ws: "wss://indexer.v4testnet.dydx.exchange/v4/ws",
};
pub fn rest_url(&self, _account_type: AccountType) -> &str {
self.indexer_rest
}
pub fn ws_url(&self, _account_type: AccountType) -> &str {
self.indexer_ws
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DydxEndpoint {
ServerTime,
BlockHeight,
PerpetualMarkets,
Orderbook,
Trades,
Candles,
HistoricalFunding,
Sparklines,
Addresses,
SpecificSubaccount,
ParentSubaccount,
AssetPositions,
Transfers,
TradingRewards,
AggregatedRewards,
PerpetualPositions,
ParentPositions,
HistoricalPnl,
ParentHistoricalPnl,
FundingPayments,
ParentFundingPayments,
Orders,
SpecificOrder,
Fills,
ParentOrders,
ParentFills,
ComplianceScreen,
TransfersBetween,
ParentAssetPositions,
ParentTransfers,
MegaVaultPnl,
MegaVaultPositions,
AllVaultsPnl,
AffiliateMetadata,
AffiliateAddress,
}
impl DydxEndpoint {
pub fn path(&self) -> &'static str {
match self {
Self::ServerTime => "/time",
Self::BlockHeight => "/height",
Self::PerpetualMarkets => "/perpetualMarkets",
Self::Orderbook => "/orderbooks/perpetualMarket/{market}",
Self::Trades => "/trades/perpetualMarket/{market}",
Self::Candles => "/candles/perpetualMarkets/{market}",
Self::HistoricalFunding => "/historicalFunding/{market}",
Self::Sparklines => "/sparklines",
Self::Addresses => "/addresses/{address}",
Self::SpecificSubaccount => "/addresses/{address}/subaccountNumber/{subaccount_number}",
Self::ParentSubaccount => "/addresses/{address}/parentSubaccountNumber/{number}",
Self::AssetPositions => "/assetPositions",
Self::Transfers => "/transfers",
Self::TradingRewards => "/historicalBlockTradingRewards/{address}",
Self::AggregatedRewards => "/historicalTradingRewardAggregations/{address}",
Self::PerpetualPositions => "/perpetualPositions",
Self::ParentPositions => "/perpetualPositions/parentSubaccountNumber",
Self::HistoricalPnl => "/historical-pnl",
Self::ParentHistoricalPnl => "/historical-pnl/parentSubaccountNumber",
Self::FundingPayments => "/fundingPayments",
Self::ParentFundingPayments => "/fundingPayments/parentSubaccount",
Self::Orders => "/orders",
Self::SpecificOrder => "/orders/{orderId}",
Self::Fills => "/fills",
Self::ParentOrders => "/orders/parentSubaccountNumber",
Self::ParentFills => "/fills/parentSubaccountNumber",
Self::ComplianceScreen => "/compliance/screen/{address}",
Self::TransfersBetween => "/transfers/between",
Self::ParentAssetPositions => "/assetPositions/parentSubaccountNumber",
Self::ParentTransfers => "/transfers/parentSubaccountNumber",
Self::MegaVaultPnl => "/vault/megavault/historicalPnl",
Self::MegaVaultPositions => "/vault/megavault/positions",
Self::AllVaultsPnl => "/vault/vaults/historicalPnl",
Self::AffiliateMetadata => "/affiliates/metadata",
Self::AffiliateAddress => "/affiliates/address",
}
}
pub fn requires_auth(&self) -> bool {
false
}
pub fn method(&self) -> &'static str {
"GET"
}
}
pub fn format_symbol(base: &str, _quote: &str, _account_type: AccountType) -> String {
format!("{}-USD", base.to_uppercase())
}
pub fn map_kline_interval(interval: &str) -> &'static str {
match interval {
"1m" => "1MIN",
"5m" => "5MINS",
"15m" => "15MINS",
"30m" => "30MINS",
"1h" => "1HOUR",
"4h" => "4HOURS",
"1d" => "1DAY",
_ => "1HOUR", }
}
pub fn normalize_symbol(symbol: &str) -> String {
let upper = symbol.to_uppercase();
let normalized = if upper.contains('/') {
upper.replace('/', "-")
} else if upper.contains('-') {
upper
} else {
format!("{}-USD", upper)
};
normalized
}
pub fn _is_valid_symbol(symbol: &str) -> bool {
symbol.contains('-') && symbol.ends_with("-USD") && symbol == symbol.to_uppercase()
}